blob: 0f9fbe2b792d962fa12c6e2ebc98df98f6f6d9df [file] [log] [blame]
/* Copyright (c) 2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) "PM8008: %s: " fmt, __func__
#include <linux/device.h>
#include <linux/regmap.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/string.h>
#define pm8008_err(reg, message, ...) \
pr_err("%s: " message, (reg)->rdesc.name, ##__VA_ARGS__)
#define pm8008_debug(reg, message, ...) \
pr_debug("%s: " message, (reg)->rdesc.name, ##__VA_ARGS__)
#define STARTUP_DELAY_USEC 20
#define VSET_STEP_SIZE_MV 1
#define VSET_STEP_MV 8
#define MISC_BASE 0x900
#define MISC_CHIP_ENABLE_REG (MISC_BASE + 0x50)
#define CHIP_ENABLE_BIT BIT(0)
#define LDO_ENABLE_REG(base) (base + 0x46)
#define ENABLE_BIT BIT(7)
#define LDO_STATUS1_REG(base) (base + 0x08)
#define VREG_READY_BIT BIT(7)
#define MODE_STATE_MASK GENMASK(1, 0)
#define MODE_STATE_NPM 3
#define MODE_STATE_LPM 2
#define MODE_STATE_BYPASS 0
#define LDO_VSET_LB_REG(base) (base + 0x40)
#define LDO_VSET_VALID_LB_REG(base) (base + 0x42)
#define LDO_MODE_CTL1_REG(base) (base + 0x45)
#define MODE_PRIMARY_MASK GENMASK(2, 0)
#define LDO_MODE_NPM 7
#define LDO_MODE_LPM 4
#define FORCED_BYPASS 2
#define LDO_STEPPER_CTL_REG(base) (base + 0x3b)
#define STEP_RATE_MASK GENMASK(1, 0)
#define LDO_PD_CTL_REG(base) (base + 0xA0)
#define STRONG_PD_EN_BIT BIT(7)
#define MAX_REG_NAME 20
#define PM8008_MAX_LDO 7
struct pm8008_chip {
struct device *dev;
struct regmap *regmap;
struct regulator_dev *rdev;
struct regulator_desc rdesc;
};
struct regulator_data {
char *name;
char *supply_name;
int hpm_min_load_ua;
int min_dropout_uv;
};
struct pm8008_regulator {
struct device *dev;
struct regmap *regmap;
struct regulator_desc rdesc;
struct regulator_dev *rdev;
struct regulator *parent_supply;
struct regulator *en_supply;
struct device_node *of_node;
u16 base;
int hpm_min_load_ua;
int min_dropout_uv;
int step_rate;
};
static struct regulator_data reg_data[] = {
/* name, parent, min load, headroom */
{"pm8008_l1", "vdd_l1_l2", 10000, 225000},
{"pm8008_l2", "vdd_l1_l2", 10000, 225000},
{"pm8008_l3", "vdd_l3_l4", 10000, 200000},
{"pm8008_l4", "vdd_l3_l4", 10000, 200000},
{"pm8008_l5", "vdd_l5", 10000, 300000},
{"pm8008_l6", "vdd_l6", 10000, 300000},
{"pm8008_l7", "vdd_l7", 10000, 300000},
};
/* common functions */
static int pm8008_read(struct regmap *regmap, u16 reg, u8 *val, int count)
{
int rc;
rc = regmap_bulk_read(regmap, reg, val, count);
if (rc < 0)
pr_err("failed to read 0x%04x\n", reg);
return rc;
}
static int pm8008_write(struct regmap *regmap, u16 reg, u8 *val, int count)
{
int rc;
pr_debug("Writing 0x%02x to 0x%04x\n", val, reg);
rc = regmap_bulk_write(regmap, reg, val, count);
if (rc < 0)
pr_err("failed to write 0x%04x\n", reg);
return rc;
}
static int pm8008_masked_write(struct regmap *regmap, u16 reg, u8 mask,
u8 val)
{
int rc;
pr_debug("Writing 0x%02x to 0x%04x with mask 0x%02x\n", val, reg, mask);
rc = regmap_update_bits(regmap, reg, mask, val);
if (rc < 0)
pr_err("failed to write 0x%02x to 0x%04x with mask 0x%02x\n",
val, reg, mask);
return rc;
}
/* PM8008 LDO Regulator callbacks */
static int pm8008_regulator_get_voltage(struct regulator_dev *rdev)
{
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
u8 vset_raw[2];
int rc;
rc = pm8008_read(pm8008_reg->regmap,
LDO_VSET_VALID_LB_REG(pm8008_reg->base),
vset_raw, 2);
if (rc < 0) {
pm8008_err(pm8008_reg,
"failed to read regulator voltage rc=%d\n", rc);
return rc;
}
pm8008_debug(pm8008_reg, "VSET read [%x][%x]\n",
vset_raw[1], vset_raw[0]);
return (vset_raw[1] << 8 | vset_raw[0]) * 1000;
}
static int pm8008_regulator_is_enabled(struct regulator_dev *rdev)
{
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
int rc;
u8 reg;
rc = pm8008_read(pm8008_reg->regmap,
LDO_ENABLE_REG(pm8008_reg->base), &reg, 1);
if (rc < 0) {
pm8008_err(pm8008_reg, "failed to read enable reg rc=%d\n", rc);
return rc;
}
return !!(reg & ENABLE_BIT);
}
static int pm8008_regulator_enable(struct regulator_dev *rdev)
{
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
int rc, init_mv, delay_us, delay_ms, retry_count = 10;
u8 reg;
rc = regulator_enable(pm8008_reg->en_supply);
if (rc < 0) {
pm8008_err(pm8008_reg,
"failed to enable en_supply rc=%d\n", rc);
return rc;
}
if (pm8008_reg->parent_supply) {
rc = regulator_enable(pm8008_reg->parent_supply);
if (rc < 0) {
pm8008_err(pm8008_reg,
"failed to enable parent rc=%d\n", rc);
regulator_disable(pm8008_reg->en_supply);
return rc;
}
}
rc = pm8008_masked_write(pm8008_reg->regmap,
LDO_ENABLE_REG(pm8008_reg->base),
ENABLE_BIT, ENABLE_BIT);
if (rc < 0) {
pm8008_err(pm8008_reg,
"failed to enable regulator rc=%d\n", rc);
goto remove_vote;
}
/*
* wait for VREG_OK
* Read voltage and calculate the delay.
*/
init_mv = pm8008_regulator_get_voltage(rdev) / 1000;
if (init_mv < 0) {
pm8008_err(pm8008_reg,
"failed to get regulator voltage rc=%d\n", rc);
goto out;
}
delay_us = STARTUP_DELAY_USEC
+ DIV_ROUND_UP(init_mv * 1000, pm8008_reg->step_rate);
delay_ms = DIV_ROUND_UP(delay_us, 1000);
/* Retry 10 times for VREG_OK before bailing out */
while (retry_count--) {
if (delay_ms > 20)
msleep(delay_ms);
else
usleep_range(delay_us, delay_us + 100);
rc = pm8008_read(pm8008_reg->regmap,
LDO_STATUS1_REG(pm8008_reg->base), &reg, 1);
if (rc < 0) {
pm8008_err(pm8008_reg,
"failed to read regulator status rc=%d\n", rc);
goto out;
}
if (reg & VREG_READY_BIT) {
pm8008_debug(pm8008_reg, "regulator enabled\n");
return 0;
}
}
pm8008_err(pm8008_reg,
"failed to enable regulator VREG_READY not set\n");
out:
pm8008_masked_write(pm8008_reg->regmap,
LDO_ENABLE_REG(pm8008_reg->base), ENABLE_BIT, 0);
remove_vote:
rc = regulator_disable(pm8008_reg->en_supply);
if (pm8008_reg->parent_supply)
rc |= regulator_disable(pm8008_reg->parent_supply);
if (rc < 0)
pm8008_err(pm8008_reg,
"failed to disable parent regulator rc=%d\n", rc);
return -ETIME;
}
static int pm8008_regulator_disable(struct regulator_dev *rdev)
{
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
int rc;
rc = pm8008_masked_write(pm8008_reg->regmap,
LDO_ENABLE_REG(pm8008_reg->base),
ENABLE_BIT, 0);
if (rc < 0) {
pm8008_err(pm8008_reg,
"failed to disable regulator rc=%d\n", rc);
return rc;
}
/* remove vote from chip enable regulator */
rc = regulator_disable(pm8008_reg->en_supply);
if (rc < 0) {
pm8008_err(pm8008_reg,
"failed to disable en_supply rc=%d\n", rc);
}
/* remove voltage vote from parent regulator */
if (pm8008_reg->parent_supply) {
rc = regulator_set_voltage(pm8008_reg->parent_supply,
0, INT_MAX);
if (rc < 0) {
pm8008_err(pm8008_reg,
"failed to remove parent voltage rc=%d\n", rc);
return rc;
}
rc = regulator_disable(pm8008_reg->parent_supply);
if (rc < 0) {
pm8008_err(pm8008_reg,
"failed to disable parent rc=%d\n", rc);
return rc;
}
}
pm8008_debug(pm8008_reg, "regulator disabled\n");
return 0;
}
static int pm8008_write_voltage(struct pm8008_regulator *pm8008_reg, int min_uv,
int max_uv)
{
int rc = 0, mv;
u8 vset_raw[2];
mv = DIV_ROUND_UP(min_uv, 1000);
if (mv * 1000 > max_uv) {
pm8008_err(pm8008_reg,
"requested voltage above maximum limit\n");
return -EINVAL;
}
/*
* Each LSB of regulator is 1mV and the voltage setpoint
* should be multiple of 8mV(step).
*/
mv = DIV_ROUND_UP(DIV_ROUND_UP(mv, VSET_STEP_MV) * VSET_STEP_MV,
VSET_STEP_SIZE_MV);
vset_raw[0] = mv & 0xff;
vset_raw[1] = (mv & 0xff00) >> 8;
rc = pm8008_write(pm8008_reg->regmap, LDO_VSET_LB_REG(pm8008_reg->base),
vset_raw, 2);
if (rc < 0) {
pm8008_err(pm8008_reg, "failed to write voltage rc=%d\n", rc);
return rc;
}
pm8008_debug(pm8008_reg, "VSET=[%x][%x]\n", vset_raw[1], vset_raw[0]);
return 0;
}
static int pm8008_regulator_set_voltage(struct regulator_dev *rdev,
int min_uv, int max_uv, unsigned int *selector)
{
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
int rc = 0;
if (pm8008_reg->parent_supply) {
/* request on parent regulator with headroom */
rc = regulator_set_voltage(pm8008_reg->parent_supply,
pm8008_reg->min_dropout_uv + min_uv,
INT_MAX);
if (rc < 0) {
pm8008_err(pm8008_reg,
"failed to request parent supply voltage rc=%d\n",
rc);
return rc;
}
}
rc = pm8008_write_voltage(pm8008_reg, min_uv, max_uv);
if (rc < 0) {
/* remove parent's voltage vote */
if (pm8008_reg->parent_supply)
regulator_set_voltage(pm8008_reg->parent_supply,
0, INT_MAX);
}
pm8008_debug(pm8008_reg, "voltage set to %d\n", min_uv);
return rc;
}
static int pm8008_regulator_set_mode(struct regulator_dev *rdev,
unsigned int mode)
{
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
int rc;
u8 val = LDO_MODE_LPM;
if (mode == REGULATOR_MODE_NORMAL)
val = LDO_MODE_NPM;
else if (mode == REGULATOR_MODE_IDLE)
val = LDO_MODE_LPM;
rc = pm8008_masked_write(pm8008_reg->regmap,
LDO_MODE_CTL1_REG(pm8008_reg->base),
MODE_PRIMARY_MASK, val);
if (!rc)
pm8008_debug(pm8008_reg, "mode set to %d\n", val);
return rc;
}
static unsigned int pm8008_regulator_get_mode(struct regulator_dev *rdev)
{
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
int rc;
u8 reg;
rc = pm8008_read(pm8008_reg->regmap,
LDO_STATUS1_REG(pm8008_reg->base), &reg, 1);
if (rc < 0) {
pm8008_err(pm8008_reg, "failed to get mode rc=%d\n", rc);
return rc;
}
return ((reg & MODE_STATE_MASK) == MODE_STATE_NPM)
? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
}
static int pm8008_regulator_set_load(struct regulator_dev *rdev, int load_uA)
{
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
int mode;
if (load_uA >= pm8008_reg->hpm_min_load_ua)
mode = REGULATOR_MODE_NORMAL;
else
mode = REGULATOR_MODE_IDLE;
return pm8008_regulator_set_mode(rdev, mode);
}
static int pm8008_regulator_set_voltage_time(struct regulator_dev *rdev,
int old_uV, int new_uv)
{
struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev);
return DIV_ROUND_UP(abs(new_uv - old_uV), pm8008_reg->step_rate);
}
static struct regulator_ops pm8008_regulator_ops = {
.enable = pm8008_regulator_enable,
.disable = pm8008_regulator_disable,
.is_enabled = pm8008_regulator_is_enabled,
.set_voltage = pm8008_regulator_set_voltage,
.get_voltage = pm8008_regulator_get_voltage,
.set_mode = pm8008_regulator_set_mode,
.get_mode = pm8008_regulator_get_mode,
.set_load = pm8008_regulator_set_load,
.set_voltage_time = pm8008_regulator_set_voltage_time,
};
static int pm8008_register_ldo(struct pm8008_regulator *pm8008_reg,
const char *name)
{
struct regulator_config reg_config = {};
struct regulator_init_data *init_data;
struct device *dev = pm8008_reg->dev;
struct device_node *reg_node = pm8008_reg->of_node;
char buff[MAX_REG_NAME];
int rc, i, init_voltage;
u8 reg;
/* get regulator data */
for (i = 0; i < PM8008_MAX_LDO; i++)
if (!strcmp(reg_data[i].name, name))
break;
if (i == PM8008_MAX_LDO) {
pr_err("Invalid regulator name %s\n", name);
return -EINVAL;
}
rc = of_property_read_u16(reg_node, "reg", &pm8008_reg->base);
if (rc < 0) {
pr_err("%s: failed to get regulator base rc=%d\n", name, rc);
return rc;
}
pm8008_reg->min_dropout_uv = reg_data[i].min_dropout_uv;
of_property_read_u32(reg_node, "qcom,min-dropout-voltage",
&pm8008_reg->min_dropout_uv);
pm8008_reg->hpm_min_load_ua = reg_data[i].hpm_min_load_ua;
of_property_read_u32(reg_node, "qcom,hpm-min-load",
&pm8008_reg->hpm_min_load_ua);
init_voltage = -EINVAL;
of_property_read_u32(reg_node, "qcom,init-voltage", &init_voltage);
if (of_property_read_bool(reg_node, "qcom,strong-pd")) {
rc = pm8008_masked_write(pm8008_reg->regmap,
LDO_PD_CTL_REG(pm8008_reg->base),
STRONG_PD_EN_BIT, STRONG_PD_EN_BIT);
if (rc < 0) {
pr_err("%s: failed to configure pull down rc=%d\n",
name, rc);
return rc;
}
}
/* get slew rate */
rc = pm8008_read(pm8008_reg->regmap,
LDO_STEPPER_CTL_REG(pm8008_reg->base), &reg, 1);
if (rc < 0) {
pr_err("%s: failed to read step rate configuration rc=%d\n",
name, rc);
return rc;
}
pm8008_reg->step_rate = 38400 >> (reg & STEP_RATE_MASK);
scnprintf(buff, MAX_REG_NAME, "%s-supply", reg_data[i].supply_name);
if (of_find_property(dev->of_node, buff, NULL)) {
pm8008_reg->parent_supply = devm_regulator_get(dev,
reg_data[i].supply_name);
if (IS_ERR(pm8008_reg->parent_supply)) {
rc = PTR_ERR(pm8008_reg->parent_supply);
if (rc != -EPROBE_DEFER)
pr_err("%s: failed to get parent regulator rc=%d\n",
name, rc);
return rc;
}
}
/* pm8008_en should be present otherwise fail the regulator probe */
pm8008_reg->en_supply = devm_regulator_get(dev, "pm8008_en");
if (IS_ERR(pm8008_reg->en_supply)) {
rc = PTR_ERR(pm8008_reg->en_supply);
pr_err("%s: failed to get chip_en supply\n", name);
return rc;
}
init_data = of_get_regulator_init_data(dev, reg_node,
&pm8008_reg->rdesc);
if (init_data == NULL) {
pr_err("%s: failed to get regulator data\n", name);
return -ENODATA;
}
if (!init_data->constraints.name) {
pr_err("%s: regulator name missing\n", name);
return -EINVAL;
}
/* configure the initial voltage for the regulator */
if (init_voltage > 0) {
rc = pm8008_write_voltage(pm8008_reg, init_voltage,
init_data->constraints.max_uV);
if (rc < 0)
pr_err("%s: failed to set initial voltage rc=%d\n",
name, rc);
}
init_data->constraints.input_uV = init_data->constraints.max_uV;
init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS
| REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_DRMS;
reg_config.dev = dev;
reg_config.init_data = init_data;
reg_config.driver_data = pm8008_reg;
reg_config.of_node = reg_node;
pm8008_reg->rdesc.owner = THIS_MODULE;
pm8008_reg->rdesc.type = REGULATOR_VOLTAGE;
pm8008_reg->rdesc.ops = &pm8008_regulator_ops;
pm8008_reg->rdesc.name = init_data->constraints.name;
pm8008_reg->rdesc.n_voltages = 1;
pm8008_reg->rdev = devm_regulator_register(dev, &pm8008_reg->rdesc,
&reg_config);
if (IS_ERR(pm8008_reg->rdev)) {
rc = PTR_ERR(pm8008_reg->rdev);
pr_err("%s: failed to register regulator rc=%d\n",
pm8008_reg->rdesc.name, rc);
return rc;
}
pr_debug("%s regulator registered\n", name);
return 0;
}
/* PMIC probe and helper function */
static int pm8008_parse_regulator(struct regmap *regmap, struct device *dev)
{
int rc = 0;
const char *name;
struct device_node *child;
struct pm8008_regulator *pm8008_reg;
/* parse each subnode and register regulator for regulator child */
for_each_available_child_of_node(dev->of_node, child) {
pm8008_reg = devm_kzalloc(dev, sizeof(*pm8008_reg), GFP_KERNEL);
if (!pm8008_reg)
return -ENOMEM;
pm8008_reg->regmap = regmap;
pm8008_reg->of_node = child;
pm8008_reg->dev = dev;
rc = of_property_read_string(child, "regulator-name", &name);
if (rc)
continue;
rc = pm8008_register_ldo(pm8008_reg, name);
if (rc < 0) {
pr_err("failed to register regulator %s rc=%d\n",
name, rc);
return rc;
}
}
return 0;
}
static int pm8008_regulator_probe(struct platform_device *pdev)
{
int rc = 0;
struct regmap *regmap;
regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!regmap) {
pr_err("parent regmap is missing\n");
return -EINVAL;
}
rc = pm8008_parse_regulator(regmap, &pdev->dev);
if (rc < 0) {
pr_err("failed to parse device tree rc=%d\n", rc);
return rc;
}
return 0;
}
/* PM8008 chip enable regulator callbacks */
static int pm8008_enable_regulator_enable(struct regulator_dev *rdev)
{
struct pm8008_regulator *chip = rdev_get_drvdata(rdev);
int rc;
rc = pm8008_masked_write(chip->regmap, MISC_CHIP_ENABLE_REG,
CHIP_ENABLE_BIT, CHIP_ENABLE_BIT);
if (rc < 0) {
pm8008_err(chip, "failed to enable chip rc=%d\n", rc);
return rc;
}
pm8008_debug(chip, "regulator enabled\n");
return 0;
}
static int pm8008_enable_regulator_disable(struct regulator_dev *rdev)
{
struct pm8008_regulator *chip = rdev_get_drvdata(rdev);
int rc;
rc = pm8008_masked_write(chip->regmap, MISC_CHIP_ENABLE_REG,
CHIP_ENABLE_BIT, 0);
if (rc < 0) {
pm8008_err(chip, "failed to disable chip rc=%d\n", rc);
return rc;
}
pm8008_debug(chip, "regulator disabled\n");
return 0;
}
static int pm8008_enable_regulator_is_enabled(struct regulator_dev *rdev)
{
struct pm8008_regulator *chip = rdev_get_drvdata(rdev);
int rc;
u8 reg;
rc = pm8008_read(chip->regmap, MISC_CHIP_ENABLE_REG, &reg, 1);
if (rc < 0) {
pm8008_err(chip, "failed to get chip state rc=%d\n", rc);
return rc;
}
return !!(reg & CHIP_ENABLE_BIT);
}
static struct regulator_ops pm8008_enable_reg_ops = {
.enable = pm8008_enable_regulator_enable,
.disable = pm8008_enable_regulator_disable,
.is_enabled = pm8008_enable_regulator_is_enabled,
};
static int pm8008_init_enable_regulator(struct pm8008_chip *chip)
{
struct regulator_config cfg = {};
int rc = 0;
cfg.dev = chip->dev;
cfg.driver_data = chip;
chip->rdesc.owner = THIS_MODULE;
chip->rdesc.type = REGULATOR_VOLTAGE;
chip->rdesc.ops = &pm8008_enable_reg_ops;
chip->rdesc.of_match = "qcom,pm8008-chip-en";
chip->rdesc.name = "qcom,pm8008-chip-en";
chip->rdev = devm_regulator_register(chip->dev, &chip->rdesc, &cfg);
if (IS_ERR(chip->rdev)) {
rc = PTR_ERR(chip->rdev);
chip->rdev = NULL;
return rc;
}
return 0;
}
static int pm8008_chip_probe(struct platform_device *pdev)
{
int rc = 0;
struct pm8008_chip *chip;
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!chip->regmap) {
pr_err("parent regmap is missing\n");
return -EINVAL;
}
chip->dev = &pdev->dev;
/* Register chip enable regulator */
rc = pm8008_init_enable_regulator(chip);
if (rc < 0) {
pr_err("Failed to register chip enable regulator rc=%d\n", rc);
return rc;
}
pr_debug("PM8008 chip registered\n");
return 0;
}
static int pm8008_chip_remove(struct platform_device *pdev)
{
struct pm8008_chip *chip = platform_get_drvdata(pdev);
int rc;
rc = pm8008_masked_write(chip->regmap, MISC_CHIP_ENABLE_REG,
CHIP_ENABLE_BIT, 0);
if (rc < 0)
pr_err("failed to disable chip rc=%d\n", rc);
return 0;
}
static const struct of_device_id pm8008_regulator_match_table[] = {
{
.compatible = "qcom,pm8008-regulator",
},
{ },
};
static struct platform_driver pm8008_regulator_driver = {
.driver = {
.name = "qcom,pm8008-regulator",
.owner = THIS_MODULE,
.of_match_table = pm8008_regulator_match_table,
},
.probe = pm8008_regulator_probe,
};
module_platform_driver(pm8008_regulator_driver);
static const struct of_device_id pm8008_chip_match_table[] = {
{
.compatible = "qcom,pm8008-chip",
},
{ },
};
static struct platform_driver pm8008_chip_driver = {
.driver = {
.name = "qcom,pm8008-chip",
.owner = THIS_MODULE,
.of_match_table = pm8008_chip_match_table,
},
.probe = pm8008_chip_probe,
.remove = pm8008_chip_remove,
};
module_platform_driver(pm8008_chip_driver);
MODULE_DESCRIPTION("QPNP PM8008 PMIC Regulator Driver");
MODULE_LICENSE("GPL v2");