1be0e2d3eSHaojian Zhuang /* 2be0e2d3eSHaojian Zhuang * Regulators driver for Marvell 88PM8607 3be0e2d3eSHaojian Zhuang * 4be0e2d3eSHaojian Zhuang * Copyright (C) 2009 Marvell International Ltd. 5be0e2d3eSHaojian Zhuang * Haojian Zhuang <haojian.zhuang@marvell.com> 6be0e2d3eSHaojian Zhuang * 7be0e2d3eSHaojian Zhuang * This program is free software; you can redistribute it and/or modify 8be0e2d3eSHaojian Zhuang * it under the terms of the GNU General Public License version 2 as 9be0e2d3eSHaojian Zhuang * published by the Free Software Foundation. 10be0e2d3eSHaojian Zhuang */ 11be0e2d3eSHaojian Zhuang #include <linux/kernel.h> 12be0e2d3eSHaojian Zhuang #include <linux/init.h> 13be0e2d3eSHaojian Zhuang #include <linux/err.h> 1453dbab7aSHaojian Zhuang #include <linux/i2c.h> 15*2e57d567SHaojian Zhuang #include <linux/of.h> 16*2e57d567SHaojian Zhuang #include <linux/regulator/of_regulator.h> 17be0e2d3eSHaojian Zhuang #include <linux/platform_device.h> 18be0e2d3eSHaojian Zhuang #include <linux/regulator/driver.h> 19be0e2d3eSHaojian Zhuang #include <linux/regulator/machine.h> 2053dbab7aSHaojian Zhuang #include <linux/mfd/88pm860x.h> 2165602c32SPaul Gortmaker #include <linux/module.h> 22be0e2d3eSHaojian Zhuang 23be0e2d3eSHaojian Zhuang struct pm8607_regulator_info { 24be0e2d3eSHaojian Zhuang struct regulator_desc desc; 2553dbab7aSHaojian Zhuang struct pm860x_chip *chip; 26be0e2d3eSHaojian Zhuang struct regulator_dev *regulator; 2753dbab7aSHaojian Zhuang struct i2c_client *i2c; 28e7a7810aSJett.Zhou struct i2c_client *i2c_8606; 29be0e2d3eSHaojian Zhuang 309f79e9dbSHaojian Zhuang unsigned int *vol_table; 319f79e9dbSHaojian Zhuang unsigned int *vol_suspend; 329f79e9dbSHaojian Zhuang 33be0e2d3eSHaojian Zhuang int update_reg; 34be0e2d3eSHaojian Zhuang int update_bit; 35be0e2d3eSHaojian Zhuang int slope_double; 36be0e2d3eSHaojian Zhuang }; 37be0e2d3eSHaojian Zhuang 389f79e9dbSHaojian Zhuang static const unsigned int BUCK1_table[] = { 399f79e9dbSHaojian Zhuang 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000, 409f79e9dbSHaojian Zhuang 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000, 419f79e9dbSHaojian Zhuang 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 429f79e9dbSHaojian Zhuang 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000, 439f79e9dbSHaojian Zhuang 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 449f79e9dbSHaojian Zhuang 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 459f79e9dbSHaojian Zhuang 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 469f79e9dbSHaojian Zhuang 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 479f79e9dbSHaojian Zhuang }; 48be0e2d3eSHaojian Zhuang 499f79e9dbSHaojian Zhuang static const unsigned int BUCK1_suspend_table[] = { 509f79e9dbSHaojian Zhuang 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 519f79e9dbSHaojian Zhuang 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 529f79e9dbSHaojian Zhuang 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 539f79e9dbSHaojian Zhuang 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 549f79e9dbSHaojian Zhuang 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000, 559f79e9dbSHaojian Zhuang 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 569f79e9dbSHaojian Zhuang 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 579f79e9dbSHaojian Zhuang 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000, 589f79e9dbSHaojian Zhuang }; 599f79e9dbSHaojian Zhuang 609f79e9dbSHaojian Zhuang static const unsigned int BUCK2_table[] = { 619f79e9dbSHaojian Zhuang 0, 50000, 100000, 150000, 200000, 250000, 300000, 350000, 629f79e9dbSHaojian Zhuang 400000, 450000, 500000, 550000, 600000, 650000, 700000, 750000, 639f79e9dbSHaojian Zhuang 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000, 649f79e9dbSHaojian Zhuang 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000, 659f79e9dbSHaojian Zhuang 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000, 669f79e9dbSHaojian Zhuang 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000, 679f79e9dbSHaojian Zhuang 2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000, 689f79e9dbSHaojian Zhuang 2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000, 699f79e9dbSHaojian Zhuang }; 709f79e9dbSHaojian Zhuang 719f79e9dbSHaojian Zhuang static const unsigned int BUCK2_suspend_table[] = { 729f79e9dbSHaojian Zhuang 0, 50000, 100000, 150000, 200000, 250000, 300000, 350000, 739f79e9dbSHaojian Zhuang 400000, 450000, 500000, 550000, 600000, 650000, 700000, 750000, 749f79e9dbSHaojian Zhuang 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000, 759f79e9dbSHaojian Zhuang 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000, 769f79e9dbSHaojian Zhuang 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000, 779f79e9dbSHaojian Zhuang 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000, 789f79e9dbSHaojian Zhuang 2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000, 799f79e9dbSHaojian Zhuang 2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000, 809f79e9dbSHaojian Zhuang }; 819f79e9dbSHaojian Zhuang 829f79e9dbSHaojian Zhuang static const unsigned int BUCK3_table[] = { 839f79e9dbSHaojian Zhuang 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 849f79e9dbSHaojian Zhuang 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 859f79e9dbSHaojian Zhuang 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 869f79e9dbSHaojian Zhuang 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 879f79e9dbSHaojian Zhuang 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000, 889f79e9dbSHaojian Zhuang 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 899f79e9dbSHaojian Zhuang 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 909f79e9dbSHaojian Zhuang 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000, 919f79e9dbSHaojian Zhuang }; 929f79e9dbSHaojian Zhuang 939f79e9dbSHaojian Zhuang static const unsigned int BUCK3_suspend_table[] = { 949f79e9dbSHaojian Zhuang 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 959f79e9dbSHaojian Zhuang 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 969f79e9dbSHaojian Zhuang 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 979f79e9dbSHaojian Zhuang 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 989f79e9dbSHaojian Zhuang 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000, 999f79e9dbSHaojian Zhuang 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1009f79e9dbSHaojian Zhuang 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1019f79e9dbSHaojian Zhuang 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000, 1029f79e9dbSHaojian Zhuang }; 1039f79e9dbSHaojian Zhuang 1049f79e9dbSHaojian Zhuang static const unsigned int LDO1_table[] = { 1059f79e9dbSHaojian Zhuang 1800000, 1200000, 2800000, 0, 1069f79e9dbSHaojian Zhuang }; 1079f79e9dbSHaojian Zhuang 1089f79e9dbSHaojian Zhuang static const unsigned int LDO1_suspend_table[] = { 1099f79e9dbSHaojian Zhuang 1800000, 1200000, 0, 0, 1109f79e9dbSHaojian Zhuang }; 1119f79e9dbSHaojian Zhuang 1129f79e9dbSHaojian Zhuang static const unsigned int LDO2_table[] = { 1139f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000, 1149f79e9dbSHaojian Zhuang }; 1159f79e9dbSHaojian Zhuang 1169f79e9dbSHaojian Zhuang static const unsigned int LDO2_suspend_table[] = { 1179f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1189f79e9dbSHaojian Zhuang }; 1199f79e9dbSHaojian Zhuang 1209f79e9dbSHaojian Zhuang static const unsigned int LDO3_table[] = { 1219f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000, 1229f79e9dbSHaojian Zhuang }; 1239f79e9dbSHaojian Zhuang 1249f79e9dbSHaojian Zhuang static const unsigned int LDO3_suspend_table[] = { 1259f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1269f79e9dbSHaojian Zhuang }; 1279f79e9dbSHaojian Zhuang 1289f79e9dbSHaojian Zhuang static const unsigned int LDO4_table[] = { 1299f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000, 1309f79e9dbSHaojian Zhuang }; 1319f79e9dbSHaojian Zhuang 1329f79e9dbSHaojian Zhuang static const unsigned int LDO4_suspend_table[] = { 1339f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000, 1349f79e9dbSHaojian Zhuang }; 1359f79e9dbSHaojian Zhuang 1369f79e9dbSHaojian Zhuang static const unsigned int LDO5_table[] = { 1379f79e9dbSHaojian Zhuang 2900000, 3000000, 3100000, 3300000, 1389f79e9dbSHaojian Zhuang }; 1399f79e9dbSHaojian Zhuang 1409f79e9dbSHaojian Zhuang static const unsigned int LDO5_suspend_table[] = { 1419f79e9dbSHaojian Zhuang 2900000, 0, 0, 0, 1429f79e9dbSHaojian Zhuang }; 1439f79e9dbSHaojian Zhuang 1449f79e9dbSHaojian Zhuang static const unsigned int LDO6_table[] = { 1459f79e9dbSHaojian Zhuang 1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000, 1469f79e9dbSHaojian Zhuang }; 1479f79e9dbSHaojian Zhuang 1489f79e9dbSHaojian Zhuang static const unsigned int LDO6_suspend_table[] = { 1499f79e9dbSHaojian Zhuang 1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000, 1509f79e9dbSHaojian Zhuang }; 1519f79e9dbSHaojian Zhuang 1529f79e9dbSHaojian Zhuang static const unsigned int LDO7_table[] = { 1539f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1549f79e9dbSHaojian Zhuang }; 1559f79e9dbSHaojian Zhuang 1569f79e9dbSHaojian Zhuang static const unsigned int LDO7_suspend_table[] = { 1579f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1589f79e9dbSHaojian Zhuang }; 1599f79e9dbSHaojian Zhuang 1609f79e9dbSHaojian Zhuang static const unsigned int LDO8_table[] = { 1619f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1629f79e9dbSHaojian Zhuang }; 1639f79e9dbSHaojian Zhuang 1649f79e9dbSHaojian Zhuang static const unsigned int LDO8_suspend_table[] = { 1659f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1669f79e9dbSHaojian Zhuang }; 1679f79e9dbSHaojian Zhuang 1689f79e9dbSHaojian Zhuang static const unsigned int LDO9_table[] = { 1699f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000, 1709f79e9dbSHaojian Zhuang }; 1719f79e9dbSHaojian Zhuang 1729f79e9dbSHaojian Zhuang static const unsigned int LDO9_suspend_table[] = { 1739f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1749f79e9dbSHaojian Zhuang }; 1759f79e9dbSHaojian Zhuang 1769f79e9dbSHaojian Zhuang static const unsigned int LDO10_table[] = { 1779f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000, 1789f79e9dbSHaojian Zhuang 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1799f79e9dbSHaojian Zhuang }; 1809f79e9dbSHaojian Zhuang 1819f79e9dbSHaojian Zhuang static const unsigned int LDO10_suspend_table[] = { 1829f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1839f79e9dbSHaojian Zhuang 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1849f79e9dbSHaojian Zhuang }; 1859f79e9dbSHaojian Zhuang 1869f79e9dbSHaojian Zhuang static const unsigned int LDO12_table[] = { 1879f79e9dbSHaojian Zhuang 1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000, 1889f79e9dbSHaojian Zhuang 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1899f79e9dbSHaojian Zhuang }; 1909f79e9dbSHaojian Zhuang 1919f79e9dbSHaojian Zhuang static const unsigned int LDO12_suspend_table[] = { 1929f79e9dbSHaojian Zhuang 1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000, 1939f79e9dbSHaojian Zhuang 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1949f79e9dbSHaojian Zhuang }; 1959f79e9dbSHaojian Zhuang 1969f79e9dbSHaojian Zhuang static const unsigned int LDO13_table[] = { 1973380643bSJett.Zhou 1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0, 1989f79e9dbSHaojian Zhuang }; 1999f79e9dbSHaojian Zhuang 2009f79e9dbSHaojian Zhuang static const unsigned int LDO13_suspend_table[] = { 2019f79e9dbSHaojian Zhuang 0, 2029f79e9dbSHaojian Zhuang }; 2039f79e9dbSHaojian Zhuang 2049f79e9dbSHaojian Zhuang static const unsigned int LDO14_table[] = { 2059f79e9dbSHaojian Zhuang 1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000, 2069f79e9dbSHaojian Zhuang }; 2079f79e9dbSHaojian Zhuang 2089f79e9dbSHaojian Zhuang static const unsigned int LDO14_suspend_table[] = { 2099f79e9dbSHaojian Zhuang 1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000, 2109f79e9dbSHaojian Zhuang }; 211be0e2d3eSHaojian Zhuang 212be0e2d3eSHaojian Zhuang static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) 213be0e2d3eSHaojian Zhuang { 214be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 215be0e2d3eSHaojian Zhuang int ret = -EINVAL; 216be0e2d3eSHaojian Zhuang 21753b6949eSAxel Lin if (info->vol_table && (index < rdev->desc->n_voltages)) { 2189f79e9dbSHaojian Zhuang ret = info->vol_table[index]; 219be0e2d3eSHaojian Zhuang if (info->slope_double) 220be0e2d3eSHaojian Zhuang ret <<= 1; 221be0e2d3eSHaojian Zhuang } 222be0e2d3eSHaojian Zhuang return ret; 223be0e2d3eSHaojian Zhuang } 224be0e2d3eSHaojian Zhuang 2254ca1e1d9SAxel Lin static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) 226be0e2d3eSHaojian Zhuang { 227be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 228c006b21fSAxel Lin uint8_t val; 229be0e2d3eSHaojian Zhuang int ret; 230be0e2d3eSHaojian Zhuang 231c006b21fSAxel Lin val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1)); 232be0e2d3eSHaojian Zhuang 233c006b21fSAxel Lin ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg, 234c006b21fSAxel Lin rdev->desc->vsel_mask, val); 235be0e2d3eSHaojian Zhuang if (ret) 236be0e2d3eSHaojian Zhuang return ret; 237be0e2d3eSHaojian Zhuang switch (info->desc.id) { 238be0e2d3eSHaojian Zhuang case PM8607_ID_BUCK1: 239be0e2d3eSHaojian Zhuang case PM8607_ID_BUCK3: 24053dbab7aSHaojian Zhuang ret = pm860x_set_bits(info->i2c, info->update_reg, 241be0e2d3eSHaojian Zhuang 1 << info->update_bit, 242be0e2d3eSHaojian Zhuang 1 << info->update_bit); 243be0e2d3eSHaojian Zhuang break; 244be0e2d3eSHaojian Zhuang } 245be0e2d3eSHaojian Zhuang return ret; 246be0e2d3eSHaojian Zhuang } 247be0e2d3eSHaojian Zhuang 248e7a7810aSJett.Zhou static int pm8606_preg_enable(struct regulator_dev *rdev) 249e7a7810aSJett.Zhou { 250e7a7810aSJett.Zhou struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 251e7a7810aSJett.Zhou 252e7a7810aSJett.Zhou return pm860x_set_bits(info->i2c, rdev->desc->enable_reg, 253e7a7810aSJett.Zhou 1 << rdev->desc->enable_mask, 0); 254e7a7810aSJett.Zhou } 255e7a7810aSJett.Zhou 256e7a7810aSJett.Zhou static int pm8606_preg_disable(struct regulator_dev *rdev) 257e7a7810aSJett.Zhou { 258e7a7810aSJett.Zhou struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 259e7a7810aSJett.Zhou 260e7a7810aSJett.Zhou return pm860x_set_bits(info->i2c, rdev->desc->enable_reg, 261e7a7810aSJett.Zhou 1 << rdev->desc->enable_mask, 262e7a7810aSJett.Zhou 1 << rdev->desc->enable_mask); 263e7a7810aSJett.Zhou } 264e7a7810aSJett.Zhou 265e7a7810aSJett.Zhou static int pm8606_preg_is_enabled(struct regulator_dev *rdev) 266e7a7810aSJett.Zhou { 267e7a7810aSJett.Zhou struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 268e7a7810aSJett.Zhou int ret; 269e7a7810aSJett.Zhou 270e7a7810aSJett.Zhou ret = pm860x_reg_read(info->i2c, rdev->desc->enable_reg); 271e7a7810aSJett.Zhou if (ret < 0) 272e7a7810aSJett.Zhou return ret; 273e7a7810aSJett.Zhou 274e7a7810aSJett.Zhou return !((unsigned char)ret & (1 << rdev->desc->enable_mask)); 275e7a7810aSJett.Zhou } 276e7a7810aSJett.Zhou 277be0e2d3eSHaojian Zhuang static struct regulator_ops pm8607_regulator_ops = { 278d3d7bcccSAxel Lin .list_voltage = pm8607_list_voltage, 2794ca1e1d9SAxel Lin .set_voltage_sel = pm8607_set_voltage_sel, 280c006b21fSAxel Lin .get_voltage_sel = regulator_get_voltage_sel_regmap, 281ef26e0dbSAxel Lin .enable = regulator_enable_regmap, 282ef26e0dbSAxel Lin .disable = regulator_disable_regmap, 283ef26e0dbSAxel Lin .is_enabled = regulator_is_enabled_regmap, 284be0e2d3eSHaojian Zhuang }; 285be0e2d3eSHaojian Zhuang 286e7a7810aSJett.Zhou static struct regulator_ops pm8606_preg_ops = { 287e7a7810aSJett.Zhou .enable = pm8606_preg_enable, 288e7a7810aSJett.Zhou .disable = pm8606_preg_disable, 289e7a7810aSJett.Zhou .is_enabled = pm8606_preg_is_enabled, 290e7a7810aSJett.Zhou }; 291e7a7810aSJett.Zhou 292e7a7810aSJett.Zhou #define PM8606_PREG(ereg, ebit) \ 293e7a7810aSJett.Zhou { \ 294e7a7810aSJett.Zhou .desc = { \ 295e7a7810aSJett.Zhou .name = "PREG", \ 296e7a7810aSJett.Zhou .ops = &pm8606_preg_ops, \ 297e7a7810aSJett.Zhou .type = REGULATOR_CURRENT, \ 298e7a7810aSJett.Zhou .id = PM8606_ID_PREG, \ 299e7a7810aSJett.Zhou .owner = THIS_MODULE, \ 300e7a7810aSJett.Zhou .enable_reg = PM8606_##ereg, \ 301e7a7810aSJett.Zhou .enable_mask = (ebit), \ 302e7a7810aSJett.Zhou }, \ 303e7a7810aSJett.Zhou } 304e7a7810aSJett.Zhou 30553b6949eSAxel Lin #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \ 306be0e2d3eSHaojian Zhuang { \ 307be0e2d3eSHaojian Zhuang .desc = { \ 3089f79e9dbSHaojian Zhuang .name = #vreg, \ 309be0e2d3eSHaojian Zhuang .ops = &pm8607_regulator_ops, \ 310be0e2d3eSHaojian Zhuang .type = REGULATOR_VOLTAGE, \ 3119f79e9dbSHaojian Zhuang .id = PM8607_ID_##vreg, \ 312be0e2d3eSHaojian Zhuang .owner = THIS_MODULE, \ 31353b6949eSAxel Lin .n_voltages = ARRAY_SIZE(vreg##_table), \ 314c006b21fSAxel Lin .vsel_reg = PM8607_##vreg, \ 315c006b21fSAxel Lin .vsel_mask = ARRAY_SIZE(vreg##_table) - 1, \ 316ef26e0dbSAxel Lin .enable_reg = PM8607_##ereg, \ 317ef26e0dbSAxel Lin .enable_mask = 1 << (ebit), \ 318be0e2d3eSHaojian Zhuang }, \ 319be0e2d3eSHaojian Zhuang .update_reg = PM8607_##ureg, \ 320be0e2d3eSHaojian Zhuang .update_bit = (ubit), \ 321be0e2d3eSHaojian Zhuang .slope_double = (0), \ 3229f79e9dbSHaojian Zhuang .vol_table = (unsigned int *)&vreg##_table, \ 3239f79e9dbSHaojian Zhuang .vol_suspend = (unsigned int *)&vreg##_suspend_table, \ 324be0e2d3eSHaojian Zhuang } 325be0e2d3eSHaojian Zhuang 32653b6949eSAxel Lin #define PM8607_LDO(_id, vreg, shift, ereg, ebit) \ 327be0e2d3eSHaojian Zhuang { \ 328be0e2d3eSHaojian Zhuang .desc = { \ 329be0e2d3eSHaojian Zhuang .name = "LDO" #_id, \ 330be0e2d3eSHaojian Zhuang .ops = &pm8607_regulator_ops, \ 331be0e2d3eSHaojian Zhuang .type = REGULATOR_VOLTAGE, \ 332be0e2d3eSHaojian Zhuang .id = PM8607_ID_LDO##_id, \ 333be0e2d3eSHaojian Zhuang .owner = THIS_MODULE, \ 33453b6949eSAxel Lin .n_voltages = ARRAY_SIZE(LDO##_id##_table), \ 335c006b21fSAxel Lin .vsel_reg = PM8607_##vreg, \ 336c006b21fSAxel Lin .vsel_mask = (ARRAY_SIZE(LDO##_id##_table) - 1) << (shift), \ 337ef26e0dbSAxel Lin .enable_reg = PM8607_##ereg, \ 338ef26e0dbSAxel Lin .enable_mask = 1 << (ebit), \ 339be0e2d3eSHaojian Zhuang }, \ 340be0e2d3eSHaojian Zhuang .slope_double = (0), \ 3419f79e9dbSHaojian Zhuang .vol_table = (unsigned int *)&LDO##_id##_table, \ 3429f79e9dbSHaojian Zhuang .vol_suspend = (unsigned int *)&LDO##_id##_suspend_table, \ 343be0e2d3eSHaojian Zhuang } 344be0e2d3eSHaojian Zhuang 345be0e2d3eSHaojian Zhuang static struct pm8607_regulator_info pm8607_regulator_info[] = { 34653b6949eSAxel Lin PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0), 34753b6949eSAxel Lin PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1), 34853b6949eSAxel Lin PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2), 349be0e2d3eSHaojian Zhuang 35053b6949eSAxel Lin PM8607_LDO(1, LDO1, 0, SUPPLIES_EN11, 3), 35153b6949eSAxel Lin PM8607_LDO(2, LDO2, 0, SUPPLIES_EN11, 4), 35253b6949eSAxel Lin PM8607_LDO(3, LDO3, 0, SUPPLIES_EN11, 5), 35353b6949eSAxel Lin PM8607_LDO(4, LDO4, 0, SUPPLIES_EN11, 6), 35453b6949eSAxel Lin PM8607_LDO(5, LDO5, 0, SUPPLIES_EN11, 7), 35553b6949eSAxel Lin PM8607_LDO(6, LDO6, 0, SUPPLIES_EN12, 0), 35653b6949eSAxel Lin PM8607_LDO(7, LDO7, 0, SUPPLIES_EN12, 1), 35753b6949eSAxel Lin PM8607_LDO(8, LDO8, 0, SUPPLIES_EN12, 2), 35853b6949eSAxel Lin PM8607_LDO(9, LDO9, 0, SUPPLIES_EN12, 3), 35953b6949eSAxel Lin PM8607_LDO(10, LDO10, 0, SUPPLIES_EN12, 4), 36053b6949eSAxel Lin PM8607_LDO(12, LDO12, 0, SUPPLIES_EN12, 5), 36153b6949eSAxel Lin PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0), 36253b6949eSAxel Lin PM8607_LDO(14, LDO14, 0, SUPPLIES_EN12, 6), 363ff13e9e2SHaojian Zhuang }; 364e7a7810aSJett.Zhou 365ff13e9e2SHaojian Zhuang static struct pm8607_regulator_info pm8606_regulator_info[] = { 366e7a7810aSJett.Zhou PM8606_PREG(PREREGULATORB, 5), 367be0e2d3eSHaojian Zhuang }; 368be0e2d3eSHaojian Zhuang 369*2e57d567SHaojian Zhuang #ifdef CONFIG_OF 370*2e57d567SHaojian Zhuang static int pm8607_regulator_dt_init(struct platform_device *pdev, 371*2e57d567SHaojian Zhuang struct pm8607_regulator_info *info, 372*2e57d567SHaojian Zhuang struct regulator_config *config) 373*2e57d567SHaojian Zhuang { 374*2e57d567SHaojian Zhuang struct device_node *nproot, *np; 375*2e57d567SHaojian Zhuang nproot = pdev->dev.parent->of_node; 376*2e57d567SHaojian Zhuang if (!nproot) 377*2e57d567SHaojian Zhuang return -ENODEV; 378*2e57d567SHaojian Zhuang nproot = of_find_node_by_name(nproot, "regulators"); 379*2e57d567SHaojian Zhuang if (!nproot) { 380*2e57d567SHaojian Zhuang dev_err(&pdev->dev, "failed to find regulators node\n"); 381*2e57d567SHaojian Zhuang return -ENODEV; 382*2e57d567SHaojian Zhuang } 383*2e57d567SHaojian Zhuang for_each_child_of_node(nproot, np) { 384*2e57d567SHaojian Zhuang if (!of_node_cmp(np->name, info->desc.name)) { 385*2e57d567SHaojian Zhuang config->init_data = 386*2e57d567SHaojian Zhuang of_get_regulator_init_data(&pdev->dev, np); 387*2e57d567SHaojian Zhuang config->of_node = np; 388*2e57d567SHaojian Zhuang break; 389*2e57d567SHaojian Zhuang } 390*2e57d567SHaojian Zhuang } 391*2e57d567SHaojian Zhuang return 0; 392*2e57d567SHaojian Zhuang } 393*2e57d567SHaojian Zhuang #else 394*2e57d567SHaojian Zhuang #define pm8607_regulator_dt_init(x, y, z) (-1) 395*2e57d567SHaojian Zhuang #endif 396*2e57d567SHaojian Zhuang 397be0e2d3eSHaojian Zhuang static int __devinit pm8607_regulator_probe(struct platform_device *pdev) 398be0e2d3eSHaojian Zhuang { 39953dbab7aSHaojian Zhuang struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); 400be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = NULL; 401586e1a17SHaojian Zhuang struct regulator_init_data *pdata = pdev->dev.platform_data; 402c172708dSMark Brown struct regulator_config config = { }; 403586e1a17SHaojian Zhuang struct resource *res; 40422aad001SHaojian Zhuang int i; 405be0e2d3eSHaojian Zhuang 40602367029SMark Brown res = platform_get_resource(pdev, IORESOURCE_REG, 0); 407ff13e9e2SHaojian Zhuang if (res) { 408ff13e9e2SHaojian Zhuang /* There're resources in 88PM8607 regulator driver */ 40922aad001SHaojian Zhuang for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { 41022aad001SHaojian Zhuang info = &pm8607_regulator_info[i]; 411a70abacbSHaojian Zhuang if (info->desc.vsel_reg == res->start) 41222aad001SHaojian Zhuang break; 41322aad001SHaojian Zhuang } 41499cd25ceSAxel Lin if (i == ARRAY_SIZE(pm8607_regulator_info)) { 41509969108SRandy Dunlap dev_err(&pdev->dev, "Failed to find regulator %llu\n", 41609969108SRandy Dunlap (unsigned long long)res->start); 417be0e2d3eSHaojian Zhuang return -EINVAL; 418be0e2d3eSHaojian Zhuang } 419ff13e9e2SHaojian Zhuang } else { 420ff13e9e2SHaojian Zhuang /* There's no resource in 88PM8606 PREG regulator driver */ 421ff13e9e2SHaojian Zhuang info = &pm8606_regulator_info[0]; 422ff13e9e2SHaojian Zhuang /* i is used to check regulator ID */ 423ff13e9e2SHaojian Zhuang i = -1; 424ff13e9e2SHaojian Zhuang } 42553dbab7aSHaojian Zhuang info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; 426e7a7810aSJett.Zhou info->i2c_8606 = (chip->id == CHIP_PM8607) ? chip->companion : 427e7a7810aSJett.Zhou chip->client; 428be0e2d3eSHaojian Zhuang info->chip = chip; 429be0e2d3eSHaojian Zhuang 43022aad001SHaojian Zhuang /* check DVC ramp slope double */ 431586e1a17SHaojian Zhuang if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double) 43222aad001SHaojian Zhuang info->slope_double = 1; 43322aad001SHaojian Zhuang 434c172708dSMark Brown config.dev = &pdev->dev; 435c172708dSMark Brown config.driver_data = info; 436c172708dSMark Brown 437*2e57d567SHaojian Zhuang if (pm8607_regulator_dt_init(pdev, info, &config)) 438*2e57d567SHaojian Zhuang if (pdata) 439*2e57d567SHaojian Zhuang config.init_data = pdata; 440*2e57d567SHaojian Zhuang 441ef26e0dbSAxel Lin if (chip->id == CHIP_PM8607) 442ef26e0dbSAxel Lin config.regmap = chip->regmap; 443ef26e0dbSAxel Lin else 444ef26e0dbSAxel Lin config.regmap = chip->regmap_companion; 445ef26e0dbSAxel Lin 446c172708dSMark Brown info->regulator = regulator_register(&info->desc, &config); 447be0e2d3eSHaojian Zhuang if (IS_ERR(info->regulator)) { 448be0e2d3eSHaojian Zhuang dev_err(&pdev->dev, "failed to register regulator %s\n", 449be0e2d3eSHaojian Zhuang info->desc.name); 450be0e2d3eSHaojian Zhuang return PTR_ERR(info->regulator); 451be0e2d3eSHaojian Zhuang } 452be0e2d3eSHaojian Zhuang 453be0e2d3eSHaojian Zhuang platform_set_drvdata(pdev, info); 454be0e2d3eSHaojian Zhuang return 0; 455be0e2d3eSHaojian Zhuang } 456be0e2d3eSHaojian Zhuang 457be0e2d3eSHaojian Zhuang static int __devexit pm8607_regulator_remove(struct platform_device *pdev) 458be0e2d3eSHaojian Zhuang { 459be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = platform_get_drvdata(pdev); 460be0e2d3eSHaojian Zhuang 461192bbb95SHaojian Zhuang platform_set_drvdata(pdev, NULL); 462be0e2d3eSHaojian Zhuang regulator_unregister(info->regulator); 463be0e2d3eSHaojian Zhuang return 0; 464be0e2d3eSHaojian Zhuang } 465be0e2d3eSHaojian Zhuang 466e7a7810aSJett.Zhou static struct platform_device_id pm8607_regulator_driver_ids[] = { 467e7a7810aSJett.Zhou { 468e7a7810aSJett.Zhou .name = "88pm860x-regulator", 469e7a7810aSJett.Zhou .driver_data = 0, 470e7a7810aSJett.Zhou }, { 471e7a7810aSJett.Zhou .name = "88pm860x-preg", 472e7a7810aSJett.Zhou .driver_data = 0, 473e7a7810aSJett.Zhou }, 474e7a7810aSJett.Zhou { }, 475e7a7810aSJett.Zhou }; 476e7a7810aSJett.Zhou MODULE_DEVICE_TABLE(platform, pm8607_regulator_driver_ids); 477e7a7810aSJett.Zhou 478192bbb95SHaojian Zhuang static struct platform_driver pm8607_regulator_driver = { 479192bbb95SHaojian Zhuang .driver = { 480192bbb95SHaojian Zhuang .name = "88pm860x-regulator", 481192bbb95SHaojian Zhuang .owner = THIS_MODULE, 482192bbb95SHaojian Zhuang }, 483192bbb95SHaojian Zhuang .probe = pm8607_regulator_probe, 484192bbb95SHaojian Zhuang .remove = __devexit_p(pm8607_regulator_remove), 485e7a7810aSJett.Zhou .id_table = pm8607_regulator_driver_ids, 486be0e2d3eSHaojian Zhuang }; 487be0e2d3eSHaojian Zhuang 488be0e2d3eSHaojian Zhuang static int __init pm8607_regulator_init(void) 489be0e2d3eSHaojian Zhuang { 490192bbb95SHaojian Zhuang return platform_driver_register(&pm8607_regulator_driver); 491be0e2d3eSHaojian Zhuang } 492be0e2d3eSHaojian Zhuang subsys_initcall(pm8607_regulator_init); 493be0e2d3eSHaojian Zhuang 494be0e2d3eSHaojian Zhuang static void __exit pm8607_regulator_exit(void) 495be0e2d3eSHaojian Zhuang { 496192bbb95SHaojian Zhuang platform_driver_unregister(&pm8607_regulator_driver); 497be0e2d3eSHaojian Zhuang } 498be0e2d3eSHaojian Zhuang module_exit(pm8607_regulator_exit); 499be0e2d3eSHaojian Zhuang 500be0e2d3eSHaojian Zhuang MODULE_LICENSE("GPL"); 501be0e2d3eSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); 502be0e2d3eSHaojian Zhuang MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC"); 503be0e2d3eSHaojian Zhuang MODULE_ALIAS("platform:88pm8607-regulator"); 504