mfd: pm8038-core: add pm8xxx-regulator device configuration data

Add pm8xxx-regulator configuration data into the pm8038-core
driver.  This adds support for PMIC PM8038 regulators.

Change-Id: I8d6e42d299141a6add3c41ca920d9186ad7fa3ee
Signed-off-by: David Collins <collinsd@codeaurora.org>
This commit is contained in:
David Collins
2011-12-06 11:35:28 -08:00
parent 7501674da4
commit 045a76e605
2 changed files with 167 additions and 4 deletions

View File

@@ -17,10 +17,12 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/string.h>
#include <linux/msm_ssbi.h> #include <linux/msm_ssbi.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/mfd/pm8xxx/pm8038.h> #include <linux/mfd/pm8xxx/pm8038.h>
#include <linux/mfd/pm8xxx/core.h> #include <linux/mfd/pm8xxx/core.h>
#include <linux/mfd/pm8xxx/regulator.h>
#define REG_HWREV 0x002 /* PMIC4 revision */ #define REG_HWREV 0x002 /* PMIC4 revision */
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */ #define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
@@ -47,6 +49,8 @@
struct pm8038 { struct pm8038 {
struct device *dev; struct device *dev;
struct pm_irq_chip *irq_chip; struct pm_irq_chip *irq_chip;
struct mfd_cell *mfd_regulators;
struct pm8xxx_regulator_core_platform_data *regulator_cdata;
u32 rev_registers; u32 rev_registers;
}; };
@@ -200,6 +204,145 @@ static struct mfd_cell debugfs_cell __devinitdata = {
.pdata_size = sizeof("pm8038-dbg"), .pdata_size = sizeof("pm8038-dbg"),
}; };
static struct pm8xxx_vreg regulator_data[] = {
/* name pc_name ctrl test hpm_min */
NLDO1200("8038_l1", 0x0AE, 0x0AF, LDO_1200),
NLDO("8038_l2", "8038_l2_pc", 0x0B0, 0x0B1, LDO_150),
PLDO("8038_l3", "8038_l3_pc", 0x0B2, 0x0B3, LDO_50),
PLDO("8038_l4", "8038_l4_pc", 0x0B4, 0x0B5, LDO_50),
PLDO("8038_l5", "8038_l5_pc", 0x0B6, 0x0B7, LDO_600),
PLDO("8038_l6", "8038_l6_pc", 0x0B8, 0x0B9, LDO_600),
PLDO("8038_l7", "8038_l7_pc", 0x0BA, 0x0BB, LDO_600),
PLDO("8038_l8", "8038_l8_pc", 0x0BC, 0x0BD, LDO_300),
PLDO("8038_l9", "8038_l9_pc", 0x0BE, 0x0BF, LDO_300),
PLDO("8038_l10", "8038_l10_pc", 0x0C0, 0x0C1, LDO_600),
PLDO("8038_l11", "8038_l11_pc", 0x0C2, 0x0C3, LDO_600),
NLDO("8038_l12", "8038_l12_pc", 0x0C4, 0x0C5, LDO_300),
PLDO("8038_l14", "8038_l14_pc", 0x0C8, 0x0C9, LDO_50),
PLDO("8038_l15", "8038_l15_pc", 0x0CA, 0x0CB, LDO_150),
NLDO1200("8038_l16", 0x0CC, 0x0CD, LDO_1200),
PLDO("8038_l17", "8038_l17_pc", 0x0CE, 0x0CF, LDO_150),
PLDO("8038_l18", "8038_l18_pc", 0x0D0, 0x0D1, LDO_50),
NLDO1200("8038_l19", 0x0D2, 0x0D3, LDO_1200),
NLDO1200("8038_l20", 0x0D4, 0x0D5, LDO_1200),
PLDO("8038_l21", "8038_l21_pc", 0x0D6, 0x0D7, LDO_150),
PLDO("8038_l22", "8038_l22_pc", 0x0D8, 0x0D9, LDO_50),
PLDO("8038_l23", "8038_l23_pc", 0x0DA, 0x0DB, LDO_50),
NLDO1200("8038_l24", 0x0DC, 0x0DD, LDO_1200),
NLDO("8038_l26", "8038_l26_pc", 0x0E0, 0x0E1, LDO_150),
NLDO1200("8038_l27", 0x0E2, 0x0E3, LDO_1200),
/* name pc_name ctrl test2 clk sleep hpm_min */
SMPS("8038_s1", "8038_s1_pc", 0x1E0, 0x1E5, 0x009, 0x1E2, SMPS_1500),
SMPS("8038_s2", "8038_s2_pc", 0x1D8, 0x1DD, 0x00A, 0x1DA, SMPS_1500),
SMPS("8038_s3", "8038_s3_pc", 0x1D0, 0x1D5, 0x00B, 0x1D2, SMPS_1500),
SMPS("8038_s4", "8038_s4_pc", 0x1E8, 0x1ED, 0x00C, 0x1EA, SMPS_1500),
/* name ctrl fts_cnfg1 pfm pwr_cnfg hpm_min */
FTSMPS("8038_s5", 0x025, 0x02E, 0x026, 0x032, SMPS_2000),
FTSMPS("8038_s6", 0x036, 0x03F, 0x037, 0x043, SMPS_2000),
/* name pc_name ctrl */
VS("8038_lvs1", "8038_lvs1_pc", 0x060),
VS("8038_lvs2", "8038_lvs2_pc", 0x062),
};
#define MAX_NAME_COMPARISON_LEN 32
static int __devinit match_regulator(
struct pm8xxx_regulator_core_platform_data *core_data, char *name)
{
int found = 0;
int i;
for (i = 0; i < ARRAY_SIZE(regulator_data); i++) {
if (regulator_data[i].rdesc.name
&& strncmp(regulator_data[i].rdesc.name, name,
MAX_NAME_COMPARISON_LEN) == 0) {
core_data->is_pin_controlled = false;
core_data->vreg = &regulator_data[i];
found = 1;
break;
} else if (regulator_data[i].rdesc_pc.name
&& strncmp(regulator_data[i].rdesc_pc.name, name,
MAX_NAME_COMPARISON_LEN) == 0) {
core_data->is_pin_controlled = true;
core_data->vreg = &regulator_data[i];
found = 1;
break;
}
}
if (!found)
pr_err("could not find a match for regulator: %s\n", name);
return found;
}
static int __devinit
pm8038_add_regulators(const struct pm8038_platform_data *pdata,
struct pm8038 *pmic, int irq_base)
{
int ret = 0;
struct mfd_cell *mfd_regulators;
struct pm8xxx_regulator_core_platform_data *cdata;
int i;
/* Add one device for each regulator used by the board. */
mfd_regulators = kzalloc(sizeof(struct mfd_cell)
* (pdata->num_regulators), GFP_KERNEL);
if (!mfd_regulators) {
pr_err("Cannot allocate %d bytes for pm8038 regulator "
"mfd cells\n", sizeof(struct mfd_cell)
* (pdata->num_regulators));
return -ENOMEM;
}
cdata = kzalloc(sizeof(struct pm8xxx_regulator_core_platform_data)
* pdata->num_regulators, GFP_KERNEL);
if (!cdata) {
pr_err("Cannot allocate %d bytes for pm8038 regulator "
"core data\n", pdata->num_regulators
* sizeof(struct pm8xxx_regulator_core_platform_data));
kfree(mfd_regulators);
return -ENOMEM;
}
for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
mutex_init(&regulator_data[i].pc_lock);
for (i = 0; i < pdata->num_regulators; i++) {
if (!pdata->regulator_pdatas[i].init_data.constraints.name) {
pr_err("name missing for regulator %d\n", i);
ret = -EINVAL;
goto bail;
}
if (!match_regulator(&cdata[i],
pdata->regulator_pdatas[i].init_data.constraints.name)) {
ret = -ENODEV;
goto bail;
}
cdata[i].pdata = &(pdata->regulator_pdatas[i]);
mfd_regulators[i].name = PM8XXX_REGULATOR_DEV_NAME;
mfd_regulators[i].id = cdata[i].pdata->id;
mfd_regulators[i].platform_data = &cdata[i];
mfd_regulators[i].pdata_size =
sizeof(struct pm8xxx_regulator_core_platform_data);
}
ret = mfd_add_devices(pmic->dev, 0, mfd_regulators,
pdata->num_regulators, NULL, irq_base);
if (ret)
goto bail;
pmic->mfd_regulators = mfd_regulators;
pmic->regulator_cdata = cdata;
return ret;
bail:
for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
mutex_destroy(&regulator_data[i].pc_lock);
kfree(mfd_regulators);
kfree(cdata);
return ret;
}
static int __devinit static int __devinit
pm8038_add_subdevices(const struct pm8038_platform_data *pdata, pm8038_add_subdevices(const struct pm8038_platform_data *pdata,
@@ -287,6 +430,15 @@ pm8038_add_subdevices(const struct pm8038_platform_data *pdata,
} }
} }
if (pdata->num_regulators > 0 && pdata->regulator_pdatas) {
ret = pm8038_add_regulators(pdata, pmic, irq_base);
if (ret) {
pr_err("Failed to add regulator subdevices ret=%d\n",
ret);
goto bail;
}
}
ret = mfd_add_devices(pmic->dev, 0, &debugfs_cell, 1, NULL, irq_base); ret = mfd_add_devices(pmic->dev, 0, &debugfs_cell, 1, NULL, irq_base);
if (ret) { if (ret) {
pr_err("Failed to add debugfs subdevice ret=%d\n", ret); pr_err("Failed to add debugfs subdevice ret=%d\n", ret);
@@ -395,6 +547,8 @@ static int __devinit pm8038_probe(struct platform_device *pdev)
err: err:
mfd_remove_devices(pmic->dev); mfd_remove_devices(pmic->dev);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
kfree(pmic->mfd_regulators);
kfree(pmic->regulator_cdata);
err_read_rev: err_read_rev:
kfree(pmic); kfree(pmic);
return rc; return rc;
@@ -404,6 +558,7 @@ static int __devexit pm8038_remove(struct platform_device *pdev)
{ {
struct pm8xxx_drvdata *drvdata; struct pm8xxx_drvdata *drvdata;
struct pm8038 *pmic = NULL; struct pm8038 *pmic = NULL;
int i;
drvdata = platform_get_drvdata(pdev); drvdata = platform_get_drvdata(pdev);
@@ -418,7 +573,12 @@ static int __devexit pm8038_remove(struct platform_device *pdev)
pm8xxx_irq_exit(pmic->irq_chip); pm8xxx_irq_exit(pmic->irq_chip);
pmic->irq_chip = NULL; pmic->irq_chip = NULL;
} }
if (pmic->mfd_regulators) {
for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
mutex_destroy(&regulator_data[i].pc_lock);
}
kfree(pmic->mfd_regulators);
kfree(pmic->regulator_cdata);
kfree(pmic); kfree(pmic);
} }

View File

@@ -26,6 +26,7 @@
#include <linux/mfd/pm8xxx/rtc.h> #include <linux/mfd/pm8xxx/rtc.h>
#include <linux/input/pmic8xxx-pwrkey.h> #include <linux/input/pmic8xxx-pwrkey.h>
#include <linux/mfd/pm8xxx/misc.h> #include <linux/mfd/pm8xxx/misc.h>
#include <linux/regulator/pm8xxx-regulator.h>
#define PM8038_CORE_DEV_NAME "pm8038-core" #define PM8038_CORE_DEV_NAME "pm8038-core"
@@ -62,6 +63,8 @@ struct pm8038_platform_data {
struct pm8xxx_rtc_platform_data *rtc_pdata; struct pm8xxx_rtc_platform_data *rtc_pdata;
struct pm8xxx_pwrkey_platform_data *pwrkey_pdata; struct pm8xxx_pwrkey_platform_data *pwrkey_pdata;
struct pm8xxx_misc_platform_data *misc_pdata; struct pm8xxx_misc_platform_data *misc_pdata;
struct pm8xxx_regulator_platform_data *regulator_pdatas;
int num_regulators;
}; };
#endif #endif