492 lines
13 KiB
C
492 lines
13 KiB
C
|
/*
|
||
|
* drivers/power/axp/axp2101/axp2101-regu.c
|
||
|
* (C) Copyright 2010-2016
|
||
|
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
|
||
|
* Pannan <pannan@allwinnertech.com>
|
||
|
*
|
||
|
* regulator driver of axp2101
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU General Public License as
|
||
|
* published by the Free Software Foundation; either version 2 of
|
||
|
* the License, or (at your option) any later version.
|
||
|
*/
|
||
|
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/err.h>
|
||
|
#include <linux/init.h>
|
||
|
#include <linux/regmap.h>
|
||
|
#include <linux/platform_device.h>
|
||
|
#include <linux/regulator/driver.h>
|
||
|
#include <linux/regulator/machine.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/power/axp_depend.h>
|
||
|
#include "../axp-core.h"
|
||
|
#include "../axp-regulator.h"
|
||
|
#include "axp2101.h"
|
||
|
#include "axp2101-regu.h"
|
||
|
|
||
|
enum AXP_REGLS {
|
||
|
VCC_DCDC1,
|
||
|
VCC_DCDC2,
|
||
|
VCC_DCDC3,
|
||
|
VCC_DCDC4,
|
||
|
VCC_LDO1,
|
||
|
VCC_LDO2,
|
||
|
VCC_LDO3,
|
||
|
VCC_LDO4,
|
||
|
VCC_LDO5,
|
||
|
VCC_LDO6,
|
||
|
VCC_LDO7,
|
||
|
VCC_LDO8,
|
||
|
VCC_LDO9,
|
||
|
VCC_LDO10,
|
||
|
VCC_LDO11,
|
||
|
VCC_DCDC5,
|
||
|
VCC_2101_MAX,
|
||
|
};
|
||
|
|
||
|
struct axp2101_regulators {
|
||
|
struct regulator_dev *regulators[VCC_2101_MAX];
|
||
|
struct axp_dev *chip;
|
||
|
};
|
||
|
|
||
|
#define AXP2101_LDO(_id, min, max, step1, vreg, shift, nbits, ereg, emask, \
|
||
|
enval, disval, switch_vol, step2, new_level, mode_addr, \
|
||
|
freq_addr, dvm_ereg, dvm_ebit, dvm_flag) \
|
||
|
AXP_LDO(AXP2101, _id, min, max, step1, vreg, shift, nbits, ereg, \
|
||
|
emask, enval, disval, switch_vol, step2, new_level, mode_addr, \
|
||
|
freq_addr, dvm_ereg, dvm_ebit, dvm_flag)
|
||
|
|
||
|
#define AXP2101_DCDC(_id, min, max, step1, vreg, shift, nbits, ereg, emask, \
|
||
|
enval, disval, switch_vol, step2, new_level, mode_addr, \
|
||
|
mode_mask, freq_addr, dvm_ereg, dvm_ebit, dvm_flag) \
|
||
|
AXP_DCDC(AXP2101, _id, min, max, step1, vreg, shift, nbits, ereg, \
|
||
|
emask, enval, disval, switch_vol, step2, new_level, \
|
||
|
mode_addr, mode_mask, freq_addr, dvm_ereg, dvm_ebit, \
|
||
|
dvm_flag)
|
||
|
|
||
|
#define AXP2101_SW(_id, min, max, step1, vreg, shift, nbits, ereg, emask, \
|
||
|
enval, disval, switch_vol, step2, new_level, mode_addr, \
|
||
|
freq_addr, dvm_ereg, dvm_ebit, dvm_flag) \
|
||
|
AXP_SW(AXP2101, _id, min, max, step1, vreg, shift, nbits, ereg, emask, \
|
||
|
enval, disval, switch_vol, step2, new_level, mode_addr, \
|
||
|
freq_addr, dvm_ereg, dvm_ebit, dvm_flag)
|
||
|
|
||
|
static struct axp_regulator_info axp2101_regulator_info[] = {
|
||
|
AXP2101_DCDC(1, 1500, 3400, 100, DCDC1, 0, 5, DCDC1EN, 0x01, 0x01, 0x00,
|
||
|
0, 1, 0, 0x81, BIT(2), 0x3B, 0, 0, 0),
|
||
|
AXP2101_DCDC(2, 500, 1540, 10, DCDC2, 0, 7, DCDC2EN, 0x02, 0x02, 0x00,
|
||
|
1200, 20, 0, 0x81, BIT(3), 0x3B, 0x83, 7, 1),
|
||
|
AXP2101_DCDC(3, 500, 1540, 10, DCDC3, 0, 7, DCDC3EN, 0x04, 0x04, 0x00,
|
||
|
1200, 20, 0, 0x81, BIT(4), 0x3B, 0x84, 7, 1),
|
||
|
AXP2101_DCDC(4, 500, 1840, 10, DCDC4, 0, 7, DCDC4EN, 0x08, 0x08, 0x00,
|
||
|
1200, 20, 0, 0x81, BIT(5), 0x3B, 0, 0, 0),
|
||
|
|
||
|
AXP2101_LDO(1, 3000, 3000, 1, LDO1, 0, 0, LDO1EN, 0x01, 0x01, 0x00, 0,
|
||
|
1, 0, 0, 0, 0, 0, 0),
|
||
|
AXP2101_LDO(2, 3000, 3000, 1, LDO2, 0, 0, LDO2EN, 0x01, 0x01, 0x00, 0,
|
||
|
1, 0, 0, 0, 0, 0, 0),
|
||
|
AXP2101_LDO(3, 500, 3500, 100, LDO3, 0, 5, LDO3EN, BIT(0), BIT(0), 0x00,
|
||
|
0, 1, 0, 0, 0, 0, 0, 0),
|
||
|
AXP2101_LDO(4, 500, 3500, 100, LDO4, 0, 5, LDO4EN, BIT(1), BIT(1), 0x00,
|
||
|
0, 1, 0, 0, 0, 0, 0, 0),
|
||
|
AXP2101_LDO(5, 500, 3500, 100, LDO5, 0, 5, LDO5EN, BIT(2), BIT(2), 0x00,
|
||
|
0, 1, 0, 0, 0, 0, 0, 0),
|
||
|
AXP2101_LDO(6, 500, 3500, 100, LDO6, 0, 5, LDO6EN, BIT(3), BIT(3), 0x00,
|
||
|
3400, 200, 0, 0, 0, 0, 0, 0),
|
||
|
AXP2101_LDO(7, 500, 3500, 100, LDO7, 0, 5, LDO7EN, BIT(4), BIT(4), 0x00,
|
||
|
0, 1, 0, 0, 0, 0, 0, 0),
|
||
|
AXP2101_LDO(8, 500, 3500, 100, LDO8, 0, 5, LDO8EN, BIT(5), BIT(5), 0x00,
|
||
|
0, 1, 0, 0, 0, 0, 0, 0),
|
||
|
AXP2101_LDO(9, 500, 1400, 50, LDO9, 0, 5, LDO9EN, BIT(6), BIT(6), 0x00,
|
||
|
0, 1, 0, 0, 0, 0, 0, 0),
|
||
|
AXP2101_LDO(10, 500, 3500, 100, LDO10, 0, 5, LDO10EN, BIT(7), BIT(7),
|
||
|
0x00, 0, 1, 0, 0, 0, 0, 0, 0),
|
||
|
AXP2101_LDO(11, 500, 1400, 50, LDO11, 0, 5, LDO11EN, BIT(0), BIT(0),
|
||
|
0x00, 0, 1, 0, 0, 0, 0, 0, 0),
|
||
|
/* dcdc5 must enable accross factory efuse to enable it */
|
||
|
AXP2101_DCDC(5, 1400, 3700, 100, DCDC5, 0, 5, DCDC5EN, 0x10, 0x10, 0x00,
|
||
|
0, 1, 0, 0x86, BIT(5), 0x3B, 0, 0, 0),
|
||
|
|
||
|
};
|
||
|
|
||
|
static struct regulator_init_data axp_regl_init_data[] = {
|
||
|
[VCC_DCDC1] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_dcdc1",
|
||
|
.min_uV = 1500000,
|
||
|
.max_uV = 3400000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
[VCC_DCDC2] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_dcdc2",
|
||
|
.min_uV = 500000,
|
||
|
.max_uV = 1540000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
[VCC_DCDC3] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_dcdc3",
|
||
|
.min_uV = 500000,
|
||
|
.max_uV = 1540000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
#ifdef CONFIG_ARCH_SUN8IW16
|
||
|
.always_on = 1,
|
||
|
#endif
|
||
|
},
|
||
|
},
|
||
|
[VCC_DCDC4] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_dcdc4",
|
||
|
.min_uV = 500000,
|
||
|
.max_uV = 1840000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
|
||
|
[VCC_LDO1] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_rtc",
|
||
|
.min_uV = 3000000,
|
||
|
.max_uV = 3000000,
|
||
|
},
|
||
|
},
|
||
|
[VCC_LDO2] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_rtc1",
|
||
|
.min_uV = 3000000,
|
||
|
.max_uV = 3000000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
[VCC_LDO3] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_aldo1",
|
||
|
.min_uV = 500000,
|
||
|
.max_uV = 3500000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
#ifdef CONFIG_ARCH_SUN8IW16
|
||
|
.always_on = 1,
|
||
|
#endif
|
||
|
},
|
||
|
},
|
||
|
[VCC_LDO4] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_aldo2",
|
||
|
.min_uV = 500000,
|
||
|
.max_uV = 3500000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
[VCC_LDO5] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_aldo3",
|
||
|
.min_uV = 500000,
|
||
|
.max_uV = 3500000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
[VCC_LDO6] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_aldo4",
|
||
|
.min_uV = 500000,
|
||
|
.max_uV = 3500000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
[VCC_LDO7] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_bldo1",
|
||
|
.min_uV = 500000,
|
||
|
.max_uV = 3500000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
[VCC_LDO8] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_bldo2",
|
||
|
.min_uV = 500000,
|
||
|
.max_uV = 3500000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
[VCC_LDO9] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_cpuldos",
|
||
|
.min_uV = 500000,
|
||
|
.max_uV = 1400000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
[VCC_LDO10] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_dldo1",
|
||
|
.min_uV = 500000,
|
||
|
.max_uV = 3500000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
[VCC_LDO11] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_dldo2",
|
||
|
.min_uV = 500000,
|
||
|
.max_uV = 1400000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
[VCC_DCDC5] = {
|
||
|
.constraints = {
|
||
|
.name = "axp2101_dcdc5",
|
||
|
.min_uV = 1400000,
|
||
|
.max_uV = 3700000,
|
||
|
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
|
||
|
| REGULATOR_CHANGE_STATUS,
|
||
|
},
|
||
|
},
|
||
|
|
||
|
};
|
||
|
|
||
|
static ssize_t workmode_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
int ret;
|
||
|
uint8_t val;
|
||
|
struct regulator_dev *rdev;
|
||
|
struct axp_regulator_info *info;
|
||
|
struct axp_regmap *regmap;
|
||
|
|
||
|
rdev = container_of(dev, struct regulator_dev, dev);
|
||
|
info = rdev_get_drvdata(rdev);
|
||
|
regmap = info->regmap;
|
||
|
|
||
|
ret = axp_regmap_read(regmap, info->mode_reg, &val);
|
||
|
if (ret)
|
||
|
return sprintf(buf, "IO ERROR\n");
|
||
|
|
||
|
if ((val & info->mode_mask) == info->mode_mask)
|
||
|
return sprintf(buf, "PWM\n");
|
||
|
else
|
||
|
return sprintf(buf, "AUTO\n");
|
||
|
}
|
||
|
|
||
|
static ssize_t workmode_store(struct device *dev, struct device_attribute *attr,
|
||
|
const char *buf, size_t count)
|
||
|
{
|
||
|
uint8_t val;
|
||
|
struct regulator_dev *rdev;
|
||
|
struct axp_regulator_info *info;
|
||
|
struct axp_regmap *regmap;
|
||
|
unsigned int mode;
|
||
|
int ret;
|
||
|
|
||
|
rdev = container_of(dev, struct regulator_dev, dev);
|
||
|
info = rdev_get_drvdata(rdev);
|
||
|
regmap = info->regmap;
|
||
|
|
||
|
ret = sscanf(buf, "%u", &mode);
|
||
|
if (ret != 1)
|
||
|
return -EINVAL;
|
||
|
|
||
|
val = !!mode;
|
||
|
if (val)
|
||
|
axp_regmap_set_bits(regmap, info->mode_reg, info->mode_mask);
|
||
|
else
|
||
|
axp_regmap_clr_bits(regmap, info->mode_reg, info->mode_mask);
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static struct device_attribute axp_regu_attrs[] = {
|
||
|
AXP_REGULATOR_ATTR(workmode),
|
||
|
};
|
||
|
|
||
|
static int axp_regu_create_attrs(struct device *dev)
|
||
|
{
|
||
|
int j, ret;
|
||
|
|
||
|
for (j = 0; j < ARRAY_SIZE(axp_regu_attrs); j++) {
|
||
|
ret = device_create_file(dev, &axp_regu_attrs[j]);
|
||
|
if (ret)
|
||
|
goto sysfs_failed;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
sysfs_failed:
|
||
|
while (j--)
|
||
|
device_remove_file(dev, &axp_regu_attrs[j]);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static s32 axp2101_regu_dependence(const char *ldo_name)
|
||
|
{
|
||
|
s32 axp2101_dependence = 0;
|
||
|
|
||
|
if (strstr(ldo_name, "dcdc1") != NULL)
|
||
|
axp2101_dependence |= AXP2101_DCDC1_BIT;
|
||
|
else if (strstr(ldo_name, "dcdc2") != NULL)
|
||
|
axp2101_dependence |= AXP2101_DCDC2_BIT;
|
||
|
else if (strstr(ldo_name, "dcdc3") != NULL)
|
||
|
axp2101_dependence |= AXP2101_DCDC3_BIT;
|
||
|
else if (strstr(ldo_name, "dcdc4") != NULL)
|
||
|
axp2101_dependence |= AXP2101_DCDC4_BIT;
|
||
|
else if (strstr(ldo_name, "aldo1") != NULL)
|
||
|
axp2101_dependence |= AXP2101_ALDO1_BIT;
|
||
|
else if (strstr(ldo_name, "aldo2") != NULL)
|
||
|
axp2101_dependence |= AXP2101_ALDO2_BIT;
|
||
|
else if (strstr(ldo_name, "aldo3") != NULL)
|
||
|
axp2101_dependence |= AXP2101_ALDO3_BIT;
|
||
|
else if (strstr(ldo_name, "aldo4") != NULL)
|
||
|
axp2101_dependence |= AXP2101_ALDO4_BIT;
|
||
|
else if (strstr(ldo_name, "bldo1") != NULL)
|
||
|
axp2101_dependence |= AXP2101_BLDO1_BIT;
|
||
|
else if (strstr(ldo_name, "bldo2") != NULL)
|
||
|
axp2101_dependence |= AXP2101_BLDO2_BIT;
|
||
|
else if (strstr(ldo_name, "dldo1") != NULL)
|
||
|
axp2101_dependence |= AXP2101_DLDO1_BIT;
|
||
|
else if (strstr(ldo_name, "dldo2") != NULL)
|
||
|
axp2101_dependence |= AXP2101_DLDO2_BIT;
|
||
|
else if (strstr(ldo_name, "cpuldos") != NULL)
|
||
|
axp2101_dependence |= AXP2101_CPULDOS_BIT;
|
||
|
else if (strstr(ldo_name, "rtc1") != NULL)
|
||
|
axp2101_dependence |= AXP2101_RTC1_BIT;
|
||
|
else if (strstr(ldo_name, "rtc") != NULL)
|
||
|
axp2101_dependence |= AXP2101_RTC_BIT;
|
||
|
else if (strstr(ldo_name, "dcdc5") != NULL)
|
||
|
axp2101_dependence |= AXP2101_DCDC5_BIT;
|
||
|
else
|
||
|
return -1;
|
||
|
|
||
|
axp2101_dependence |= (0 << 30);
|
||
|
return axp2101_dependence;
|
||
|
}
|
||
|
|
||
|
static int axp2101_regulator_probe(struct platform_device *pdev)
|
||
|
{
|
||
|
s32 i, ret = 0;
|
||
|
struct axp_regulator_info *info;
|
||
|
struct axp2101_regulators *regu_data;
|
||
|
struct axp_dev *axp_dev = dev_get_drvdata(pdev->dev.parent);
|
||
|
|
||
|
if (pdev->dev.of_node) {
|
||
|
ret = axp_regulator_dt_parse(pdev->dev.of_node,
|
||
|
axp_regl_init_data,
|
||
|
axp2101_regu_dependence);
|
||
|
if (ret) {
|
||
|
pr_err("%s parse device tree err\n", __func__);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
} else {
|
||
|
pr_err("axp2101 regulator device tree err!\n");
|
||
|
return -EBUSY;
|
||
|
}
|
||
|
|
||
|
regu_data = devm_kzalloc(&pdev->dev, sizeof(*regu_data), GFP_KERNEL);
|
||
|
|
||
|
if (!regu_data)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
regu_data->chip = axp_dev;
|
||
|
platform_set_drvdata(pdev, regu_data);
|
||
|
|
||
|
/*
|
||
|
* set dcdc1 mode to pwm
|
||
|
* dcdc1 always load high
|
||
|
*/
|
||
|
axp_regmap_set_bits(axp_dev->regmap, AXP2101_DCDCMODE, BIT(2));
|
||
|
|
||
|
for (i = 0; i < VCC_2101_MAX; i++) {
|
||
|
info = &axp2101_regulator_info[i];
|
||
|
info->pmu_num = axp_dev->pmu_num;
|
||
|
regu_data->regulators[i] = axp_regulator_register(&pdev->dev,
|
||
|
axp_dev->regmap, &axp_regl_init_data[i], info);
|
||
|
|
||
|
if (IS_ERR(regu_data->regulators[i])) {
|
||
|
dev_err(&pdev->dev, "failed to register regulator %s\n",
|
||
|
info->desc.name);
|
||
|
while (--i >= 0)
|
||
|
axp_regulator_unregister(
|
||
|
regu_data->regulators[i]);
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (info->desc.id >= AXP_DCDC_ID_START) {
|
||
|
ret = axp_regu_create_attrs(
|
||
|
®u_data->regulators[i]->dev);
|
||
|
if (ret)
|
||
|
dev_err(&pdev->dev,
|
||
|
"failed to register regulator attr %s\n",
|
||
|
info->desc.name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* voltage not to the OTP default when wakeup */
|
||
|
/* axp_regmap_set_bits(axp_dev->regmap, axp2101_TEMPERATURE, 0x02); */
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int axp2101_regulator_remove(struct platform_device *pdev)
|
||
|
{
|
||
|
struct axp2101_regulators *regu_data = platform_get_drvdata(pdev);
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < VCC_2101_MAX; i++)
|
||
|
regulator_unregister(regu_data->regulators[i]);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
static const struct of_device_id axp2101_regu_dt_ids[] = {
|
||
|
{
|
||
|
.compatible = "axp2101-regulator",
|
||
|
},
|
||
|
{},
|
||
|
};
|
||
|
MODULE_DEVICE_TABLE(of, axp2101_regu_dt_ids);
|
||
|
|
||
|
static struct platform_driver axp2101_regulator_driver = {
|
||
|
.driver = {
|
||
|
.name = "axp2101-regulator",
|
||
|
.of_match_table = axp2101_regu_dt_ids,
|
||
|
},
|
||
|
.probe = axp2101_regulator_probe,
|
||
|
.remove = axp2101_regulator_remove,
|
||
|
};
|
||
|
|
||
|
static int __init axp2101_regulator_initcall(void)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
ret = platform_driver_register(&axp2101_regulator_driver);
|
||
|
if (IS_ERR_VALUE(ret)) {
|
||
|
pr_err("%s: failed, errno %d\n", __func__, ret);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
subsys_initcall(axp2101_regulator_initcall);
|
||
|
|
||
|
MODULE_DESCRIPTION("Regulator Driver of AXP2101");
|
||
|
MODULE_AUTHOR("pannan");
|
||
|
MODULE_LICENSE("GPL");
|