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> 15be0e2d3eSHaojian Zhuang #include <linux/platform_device.h> 16be0e2d3eSHaojian Zhuang #include <linux/regulator/driver.h> 17be0e2d3eSHaojian Zhuang #include <linux/regulator/machine.h> 1853dbab7aSHaojian Zhuang #include <linux/mfd/88pm860x.h> 1965602c32SPaul Gortmaker #include <linux/module.h> 20be0e2d3eSHaojian Zhuang 21be0e2d3eSHaojian Zhuang struct pm8607_regulator_info { 22be0e2d3eSHaojian Zhuang struct regulator_desc desc; 2353dbab7aSHaojian Zhuang struct pm860x_chip *chip; 24be0e2d3eSHaojian Zhuang struct regulator_dev *regulator; 2553dbab7aSHaojian Zhuang struct i2c_client *i2c; 26be0e2d3eSHaojian Zhuang 279f79e9dbSHaojian Zhuang unsigned int *vol_table; 289f79e9dbSHaojian Zhuang unsigned int *vol_suspend; 299f79e9dbSHaojian Zhuang 30be0e2d3eSHaojian Zhuang int vol_reg; 31be0e2d3eSHaojian Zhuang int vol_shift; 32be0e2d3eSHaojian Zhuang int update_reg; 33be0e2d3eSHaojian Zhuang int update_bit; 34be0e2d3eSHaojian Zhuang int enable_reg; 35be0e2d3eSHaojian Zhuang int enable_bit; 36be0e2d3eSHaojian Zhuang int slope_double; 37be0e2d3eSHaojian Zhuang }; 38be0e2d3eSHaojian Zhuang 399f79e9dbSHaojian Zhuang static const unsigned int BUCK1_table[] = { 409f79e9dbSHaojian Zhuang 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000, 419f79e9dbSHaojian Zhuang 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000, 429f79e9dbSHaojian Zhuang 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 439f79e9dbSHaojian Zhuang 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000, 449f79e9dbSHaojian Zhuang 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 459f79e9dbSHaojian Zhuang 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 469f79e9dbSHaojian Zhuang 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 479f79e9dbSHaojian Zhuang 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 489f79e9dbSHaojian Zhuang }; 49be0e2d3eSHaojian Zhuang 509f79e9dbSHaojian Zhuang static const unsigned int BUCK1_suspend_table[] = { 519f79e9dbSHaojian Zhuang 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 529f79e9dbSHaojian Zhuang 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 539f79e9dbSHaojian Zhuang 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 549f79e9dbSHaojian Zhuang 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 559f79e9dbSHaojian Zhuang 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000, 569f79e9dbSHaojian Zhuang 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 579f79e9dbSHaojian Zhuang 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 589f79e9dbSHaojian Zhuang 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000, 599f79e9dbSHaojian Zhuang }; 609f79e9dbSHaojian Zhuang 619f79e9dbSHaojian Zhuang static const unsigned int BUCK2_table[] = { 629f79e9dbSHaojian Zhuang 0, 50000, 100000, 150000, 200000, 250000, 300000, 350000, 639f79e9dbSHaojian Zhuang 400000, 450000, 500000, 550000, 600000, 650000, 700000, 750000, 649f79e9dbSHaojian Zhuang 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000, 659f79e9dbSHaojian Zhuang 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000, 669f79e9dbSHaojian Zhuang 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000, 679f79e9dbSHaojian Zhuang 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000, 689f79e9dbSHaojian Zhuang 2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000, 699f79e9dbSHaojian Zhuang 2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000, 709f79e9dbSHaojian Zhuang }; 719f79e9dbSHaojian Zhuang 729f79e9dbSHaojian Zhuang static const unsigned int BUCK2_suspend_table[] = { 739f79e9dbSHaojian Zhuang 0, 50000, 100000, 150000, 200000, 250000, 300000, 350000, 749f79e9dbSHaojian Zhuang 400000, 450000, 500000, 550000, 600000, 650000, 700000, 750000, 759f79e9dbSHaojian Zhuang 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000, 769f79e9dbSHaojian Zhuang 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000, 779f79e9dbSHaojian Zhuang 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000, 789f79e9dbSHaojian Zhuang 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000, 799f79e9dbSHaojian Zhuang 2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000, 809f79e9dbSHaojian Zhuang 2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000, 819f79e9dbSHaojian Zhuang }; 829f79e9dbSHaojian Zhuang 839f79e9dbSHaojian Zhuang static const unsigned int BUCK3_table[] = { 849f79e9dbSHaojian Zhuang 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 859f79e9dbSHaojian Zhuang 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 869f79e9dbSHaojian Zhuang 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 879f79e9dbSHaojian Zhuang 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 889f79e9dbSHaojian Zhuang 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000, 899f79e9dbSHaojian Zhuang 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 909f79e9dbSHaojian Zhuang 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 919f79e9dbSHaojian Zhuang 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000, 929f79e9dbSHaojian Zhuang }; 939f79e9dbSHaojian Zhuang 949f79e9dbSHaojian Zhuang static const unsigned int BUCK3_suspend_table[] = { 959f79e9dbSHaojian Zhuang 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 969f79e9dbSHaojian Zhuang 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 979f79e9dbSHaojian Zhuang 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 989f79e9dbSHaojian Zhuang 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 999f79e9dbSHaojian Zhuang 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000, 1009f79e9dbSHaojian Zhuang 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1019f79e9dbSHaojian Zhuang 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1029f79e9dbSHaojian Zhuang 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000, 1039f79e9dbSHaojian Zhuang }; 1049f79e9dbSHaojian Zhuang 1059f79e9dbSHaojian Zhuang static const unsigned int LDO1_table[] = { 1069f79e9dbSHaojian Zhuang 1800000, 1200000, 2800000, 0, 1079f79e9dbSHaojian Zhuang }; 1089f79e9dbSHaojian Zhuang 1099f79e9dbSHaojian Zhuang static const unsigned int LDO1_suspend_table[] = { 1109f79e9dbSHaojian Zhuang 1800000, 1200000, 0, 0, 1119f79e9dbSHaojian Zhuang }; 1129f79e9dbSHaojian Zhuang 1139f79e9dbSHaojian Zhuang static const unsigned int LDO2_table[] = { 1149f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000, 1159f79e9dbSHaojian Zhuang }; 1169f79e9dbSHaojian Zhuang 1179f79e9dbSHaojian Zhuang static const unsigned int LDO2_suspend_table[] = { 1189f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1199f79e9dbSHaojian Zhuang }; 1209f79e9dbSHaojian Zhuang 1219f79e9dbSHaojian Zhuang static const unsigned int LDO3_table[] = { 1229f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000, 1239f79e9dbSHaojian Zhuang }; 1249f79e9dbSHaojian Zhuang 1259f79e9dbSHaojian Zhuang static const unsigned int LDO3_suspend_table[] = { 1269f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1279f79e9dbSHaojian Zhuang }; 1289f79e9dbSHaojian Zhuang 1299f79e9dbSHaojian Zhuang static const unsigned int LDO4_table[] = { 1309f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000, 1319f79e9dbSHaojian Zhuang }; 1329f79e9dbSHaojian Zhuang 1339f79e9dbSHaojian Zhuang static const unsigned int LDO4_suspend_table[] = { 1349f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000, 1359f79e9dbSHaojian Zhuang }; 1369f79e9dbSHaojian Zhuang 1379f79e9dbSHaojian Zhuang static const unsigned int LDO5_table[] = { 1389f79e9dbSHaojian Zhuang 2900000, 3000000, 3100000, 3300000, 1399f79e9dbSHaojian Zhuang }; 1409f79e9dbSHaojian Zhuang 1419f79e9dbSHaojian Zhuang static const unsigned int LDO5_suspend_table[] = { 1429f79e9dbSHaojian Zhuang 2900000, 0, 0, 0, 1439f79e9dbSHaojian Zhuang }; 1449f79e9dbSHaojian Zhuang 1459f79e9dbSHaojian Zhuang static const unsigned int LDO6_table[] = { 1469f79e9dbSHaojian Zhuang 1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000, 1479f79e9dbSHaojian Zhuang }; 1489f79e9dbSHaojian Zhuang 1499f79e9dbSHaojian Zhuang static const unsigned int LDO6_suspend_table[] = { 1509f79e9dbSHaojian Zhuang 1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000, 1519f79e9dbSHaojian Zhuang }; 1529f79e9dbSHaojian Zhuang 1539f79e9dbSHaojian Zhuang static const unsigned int LDO7_table[] = { 1549f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1559f79e9dbSHaojian Zhuang }; 1569f79e9dbSHaojian Zhuang 1579f79e9dbSHaojian Zhuang static const unsigned int LDO7_suspend_table[] = { 1589f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1599f79e9dbSHaojian Zhuang }; 1609f79e9dbSHaojian Zhuang 1619f79e9dbSHaojian Zhuang static const unsigned int LDO8_table[] = { 1629f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1639f79e9dbSHaojian Zhuang }; 1649f79e9dbSHaojian Zhuang 1659f79e9dbSHaojian Zhuang static const unsigned int LDO8_suspend_table[] = { 1669f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1679f79e9dbSHaojian Zhuang }; 1689f79e9dbSHaojian Zhuang 1699f79e9dbSHaojian Zhuang static const unsigned int LDO9_table[] = { 1709f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000, 1719f79e9dbSHaojian Zhuang }; 1729f79e9dbSHaojian Zhuang 1739f79e9dbSHaojian Zhuang static const unsigned int LDO9_suspend_table[] = { 1749f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1759f79e9dbSHaojian Zhuang }; 1769f79e9dbSHaojian Zhuang 1779f79e9dbSHaojian Zhuang static const unsigned int LDO10_table[] = { 1789f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000, 1799f79e9dbSHaojian Zhuang 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1809f79e9dbSHaojian Zhuang }; 1819f79e9dbSHaojian Zhuang 1829f79e9dbSHaojian Zhuang static const unsigned int LDO10_suspend_table[] = { 1839f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1849f79e9dbSHaojian Zhuang 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1859f79e9dbSHaojian Zhuang }; 1869f79e9dbSHaojian Zhuang 1879f79e9dbSHaojian Zhuang static const unsigned int LDO12_table[] = { 1889f79e9dbSHaojian Zhuang 1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000, 1899f79e9dbSHaojian Zhuang 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1909f79e9dbSHaojian Zhuang }; 1919f79e9dbSHaojian Zhuang 1929f79e9dbSHaojian Zhuang static const unsigned int LDO12_suspend_table[] = { 1939f79e9dbSHaojian Zhuang 1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000, 1949f79e9dbSHaojian Zhuang 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1959f79e9dbSHaojian Zhuang }; 1969f79e9dbSHaojian Zhuang 1979f79e9dbSHaojian Zhuang static const unsigned int LDO13_table[] = { 1983380643bSJett.Zhou 1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0, 1999f79e9dbSHaojian Zhuang }; 2009f79e9dbSHaojian Zhuang 2019f79e9dbSHaojian Zhuang static const unsigned int LDO13_suspend_table[] = { 2029f79e9dbSHaojian Zhuang 0, 2039f79e9dbSHaojian Zhuang }; 2049f79e9dbSHaojian Zhuang 2059f79e9dbSHaojian Zhuang static const unsigned int LDO14_table[] = { 2069f79e9dbSHaojian Zhuang 1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000, 2079f79e9dbSHaojian Zhuang }; 2089f79e9dbSHaojian Zhuang 2099f79e9dbSHaojian Zhuang static const unsigned int LDO14_suspend_table[] = { 2109f79e9dbSHaojian Zhuang 1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000, 2119f79e9dbSHaojian Zhuang }; 212be0e2d3eSHaojian Zhuang 213be0e2d3eSHaojian Zhuang static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) 214be0e2d3eSHaojian Zhuang { 215be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 216be0e2d3eSHaojian Zhuang int ret = -EINVAL; 217be0e2d3eSHaojian Zhuang 21853b6949eSAxel Lin if (info->vol_table && (index < rdev->desc->n_voltages)) { 2199f79e9dbSHaojian Zhuang ret = info->vol_table[index]; 220be0e2d3eSHaojian Zhuang if (info->slope_double) 221be0e2d3eSHaojian Zhuang ret <<= 1; 222be0e2d3eSHaojian Zhuang } 223be0e2d3eSHaojian Zhuang return ret; 224be0e2d3eSHaojian Zhuang } 225be0e2d3eSHaojian Zhuang 2264ca1e1d9SAxel Lin static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) 227be0e2d3eSHaojian Zhuang { 228be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 229be0e2d3eSHaojian Zhuang uint8_t val, mask; 230be0e2d3eSHaojian Zhuang int ret; 231be0e2d3eSHaojian Zhuang 2324ca1e1d9SAxel Lin val = (uint8_t)(selector << info->vol_shift); 23353b6949eSAxel Lin mask = (rdev->desc->n_voltages - 1) << info->vol_shift; 234be0e2d3eSHaojian Zhuang 2354ca1e1d9SAxel Lin ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, selector); 236be0e2d3eSHaojian Zhuang if (ret) 237be0e2d3eSHaojian Zhuang return ret; 238be0e2d3eSHaojian Zhuang switch (info->desc.id) { 239be0e2d3eSHaojian Zhuang case PM8607_ID_BUCK1: 240be0e2d3eSHaojian Zhuang case PM8607_ID_BUCK3: 24153dbab7aSHaojian Zhuang ret = pm860x_set_bits(info->i2c, info->update_reg, 242be0e2d3eSHaojian Zhuang 1 << info->update_bit, 243be0e2d3eSHaojian Zhuang 1 << info->update_bit); 244be0e2d3eSHaojian Zhuang break; 245be0e2d3eSHaojian Zhuang } 246be0e2d3eSHaojian Zhuang return ret; 247be0e2d3eSHaojian Zhuang } 248be0e2d3eSHaojian Zhuang 249509cbf84SAxel Lin static int pm8607_get_voltage_sel(struct regulator_dev *rdev) 250be0e2d3eSHaojian Zhuang { 251be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 252be0e2d3eSHaojian Zhuang uint8_t val, mask; 253be0e2d3eSHaojian Zhuang int ret; 254be0e2d3eSHaojian Zhuang 25553dbab7aSHaojian Zhuang ret = pm860x_reg_read(info->i2c, info->vol_reg); 256be0e2d3eSHaojian Zhuang if (ret < 0) 257be0e2d3eSHaojian Zhuang return ret; 258be0e2d3eSHaojian Zhuang 25953b6949eSAxel Lin mask = (rdev->desc->n_voltages - 1) << info->vol_shift; 260be0e2d3eSHaojian Zhuang val = ((unsigned char)ret & mask) >> info->vol_shift; 261be0e2d3eSHaojian Zhuang 262509cbf84SAxel Lin return val; 263be0e2d3eSHaojian Zhuang } 264be0e2d3eSHaojian Zhuang 265be0e2d3eSHaojian Zhuang static int pm8607_enable(struct regulator_dev *rdev) 266be0e2d3eSHaojian Zhuang { 267be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 268be0e2d3eSHaojian Zhuang 26953dbab7aSHaojian Zhuang return pm860x_set_bits(info->i2c, info->enable_reg, 270be0e2d3eSHaojian Zhuang 1 << info->enable_bit, 271be0e2d3eSHaojian Zhuang 1 << info->enable_bit); 272be0e2d3eSHaojian Zhuang } 273be0e2d3eSHaojian Zhuang 274be0e2d3eSHaojian Zhuang static int pm8607_disable(struct regulator_dev *rdev) 275be0e2d3eSHaojian Zhuang { 276be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 277be0e2d3eSHaojian Zhuang 27853dbab7aSHaojian Zhuang return pm860x_set_bits(info->i2c, info->enable_reg, 279be0e2d3eSHaojian Zhuang 1 << info->enable_bit, 0); 280be0e2d3eSHaojian Zhuang } 281be0e2d3eSHaojian Zhuang 282be0e2d3eSHaojian Zhuang static int pm8607_is_enabled(struct regulator_dev *rdev) 283be0e2d3eSHaojian Zhuang { 284be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 285be0e2d3eSHaojian Zhuang int ret; 286be0e2d3eSHaojian Zhuang 28753dbab7aSHaojian Zhuang ret = pm860x_reg_read(info->i2c, info->enable_reg); 288be0e2d3eSHaojian Zhuang if (ret < 0) 289be0e2d3eSHaojian Zhuang return ret; 290be0e2d3eSHaojian Zhuang 291be0e2d3eSHaojian Zhuang return !!((unsigned char)ret & (1 << info->enable_bit)); 292be0e2d3eSHaojian Zhuang } 293be0e2d3eSHaojian Zhuang 294be0e2d3eSHaojian Zhuang static struct regulator_ops pm8607_regulator_ops = { 295d3d7bcccSAxel Lin .list_voltage = pm8607_list_voltage, 2964ca1e1d9SAxel Lin .set_voltage_sel = pm8607_set_voltage_sel, 297509cbf84SAxel Lin .get_voltage_sel = pm8607_get_voltage_sel, 298be0e2d3eSHaojian Zhuang .enable = pm8607_enable, 299be0e2d3eSHaojian Zhuang .disable = pm8607_disable, 300be0e2d3eSHaojian Zhuang .is_enabled = pm8607_is_enabled, 301be0e2d3eSHaojian Zhuang }; 302be0e2d3eSHaojian Zhuang 30353b6949eSAxel Lin #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \ 304be0e2d3eSHaojian Zhuang { \ 305be0e2d3eSHaojian Zhuang .desc = { \ 3069f79e9dbSHaojian Zhuang .name = #vreg, \ 307be0e2d3eSHaojian Zhuang .ops = &pm8607_regulator_ops, \ 308be0e2d3eSHaojian Zhuang .type = REGULATOR_VOLTAGE, \ 3099f79e9dbSHaojian Zhuang .id = PM8607_ID_##vreg, \ 310be0e2d3eSHaojian Zhuang .owner = THIS_MODULE, \ 31153b6949eSAxel Lin .n_voltages = ARRAY_SIZE(vreg##_table), \ 312be0e2d3eSHaojian Zhuang }, \ 313be0e2d3eSHaojian Zhuang .vol_reg = PM8607_##vreg, \ 314be0e2d3eSHaojian Zhuang .vol_shift = (0), \ 315be0e2d3eSHaojian Zhuang .update_reg = PM8607_##ureg, \ 316be0e2d3eSHaojian Zhuang .update_bit = (ubit), \ 317be0e2d3eSHaojian Zhuang .enable_reg = PM8607_##ereg, \ 318be0e2d3eSHaojian Zhuang .enable_bit = (ebit), \ 319be0e2d3eSHaojian Zhuang .slope_double = (0), \ 3209f79e9dbSHaojian Zhuang .vol_table = (unsigned int *)&vreg##_table, \ 3219f79e9dbSHaojian Zhuang .vol_suspend = (unsigned int *)&vreg##_suspend_table, \ 322be0e2d3eSHaojian Zhuang } 323be0e2d3eSHaojian Zhuang 32453b6949eSAxel Lin #define PM8607_LDO(_id, vreg, shift, ereg, ebit) \ 325be0e2d3eSHaojian Zhuang { \ 326be0e2d3eSHaojian Zhuang .desc = { \ 327be0e2d3eSHaojian Zhuang .name = "LDO" #_id, \ 328be0e2d3eSHaojian Zhuang .ops = &pm8607_regulator_ops, \ 329be0e2d3eSHaojian Zhuang .type = REGULATOR_VOLTAGE, \ 330be0e2d3eSHaojian Zhuang .id = PM8607_ID_LDO##_id, \ 331be0e2d3eSHaojian Zhuang .owner = THIS_MODULE, \ 33253b6949eSAxel Lin .n_voltages = ARRAY_SIZE(LDO##_id##_table), \ 333be0e2d3eSHaojian Zhuang }, \ 334be0e2d3eSHaojian Zhuang .vol_reg = PM8607_##vreg, \ 335be0e2d3eSHaojian Zhuang .vol_shift = (shift), \ 336be0e2d3eSHaojian Zhuang .enable_reg = PM8607_##ereg, \ 337be0e2d3eSHaojian Zhuang .enable_bit = (ebit), \ 338be0e2d3eSHaojian Zhuang .slope_double = (0), \ 3399f79e9dbSHaojian Zhuang .vol_table = (unsigned int *)&LDO##_id##_table, \ 3409f79e9dbSHaojian Zhuang .vol_suspend = (unsigned int *)&LDO##_id##_suspend_table, \ 341be0e2d3eSHaojian Zhuang } 342be0e2d3eSHaojian Zhuang 343be0e2d3eSHaojian Zhuang static struct pm8607_regulator_info pm8607_regulator_info[] = { 34453b6949eSAxel Lin PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0), 34553b6949eSAxel Lin PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1), 34653b6949eSAxel Lin PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2), 347be0e2d3eSHaojian Zhuang 34853b6949eSAxel Lin PM8607_LDO(1, LDO1, 0, SUPPLIES_EN11, 3), 34953b6949eSAxel Lin PM8607_LDO(2, LDO2, 0, SUPPLIES_EN11, 4), 35053b6949eSAxel Lin PM8607_LDO(3, LDO3, 0, SUPPLIES_EN11, 5), 35153b6949eSAxel Lin PM8607_LDO(4, LDO4, 0, SUPPLIES_EN11, 6), 35253b6949eSAxel Lin PM8607_LDO(5, LDO5, 0, SUPPLIES_EN11, 7), 35353b6949eSAxel Lin PM8607_LDO(6, LDO6, 0, SUPPLIES_EN12, 0), 35453b6949eSAxel Lin PM8607_LDO(7, LDO7, 0, SUPPLIES_EN12, 1), 35553b6949eSAxel Lin PM8607_LDO(8, LDO8, 0, SUPPLIES_EN12, 2), 35653b6949eSAxel Lin PM8607_LDO(9, LDO9, 0, SUPPLIES_EN12, 3), 35753b6949eSAxel Lin PM8607_LDO(10, LDO10, 0, SUPPLIES_EN12, 4), 35853b6949eSAxel Lin PM8607_LDO(12, LDO12, 0, SUPPLIES_EN12, 5), 35953b6949eSAxel Lin PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0), 36053b6949eSAxel Lin PM8607_LDO(14, LDO14, 0, SUPPLIES_EN12, 6), 361be0e2d3eSHaojian Zhuang }; 362be0e2d3eSHaojian Zhuang 363be0e2d3eSHaojian Zhuang static int __devinit pm8607_regulator_probe(struct platform_device *pdev) 364be0e2d3eSHaojian Zhuang { 36553dbab7aSHaojian Zhuang struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); 366be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = NULL; 367586e1a17SHaojian Zhuang struct regulator_init_data *pdata = pdev->dev.platform_data; 368*c172708dSMark Brown struct regulator_config config = { }; 369586e1a17SHaojian Zhuang struct resource *res; 37022aad001SHaojian Zhuang int i; 371be0e2d3eSHaojian Zhuang 372586e1a17SHaojian Zhuang res = platform_get_resource(pdev, IORESOURCE_IO, 0); 373586e1a17SHaojian Zhuang if (res == NULL) { 374586e1a17SHaojian Zhuang dev_err(&pdev->dev, "No I/O resource!\n"); 37522aad001SHaojian Zhuang return -EINVAL; 376586e1a17SHaojian Zhuang } 37722aad001SHaojian Zhuang for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { 37822aad001SHaojian Zhuang info = &pm8607_regulator_info[i]; 379586e1a17SHaojian Zhuang if (info->desc.id == res->start) 38022aad001SHaojian Zhuang break; 38122aad001SHaojian Zhuang } 38299cd25ceSAxel Lin if (i == ARRAY_SIZE(pm8607_regulator_info)) { 38309969108SRandy Dunlap dev_err(&pdev->dev, "Failed to find regulator %llu\n", 38409969108SRandy Dunlap (unsigned long long)res->start); 385be0e2d3eSHaojian Zhuang return -EINVAL; 386be0e2d3eSHaojian Zhuang } 38753dbab7aSHaojian Zhuang info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; 388be0e2d3eSHaojian Zhuang info->chip = chip; 389be0e2d3eSHaojian Zhuang 39022aad001SHaojian Zhuang /* check DVC ramp slope double */ 391586e1a17SHaojian Zhuang if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double) 39222aad001SHaojian Zhuang info->slope_double = 1; 39322aad001SHaojian Zhuang 394*c172708dSMark Brown config.dev = &pdev->dev; 395*c172708dSMark Brown config.init_data = pdata; 396*c172708dSMark Brown config.driver_data = info; 397*c172708dSMark Brown 398586e1a17SHaojian Zhuang /* replace driver_data with info */ 399*c172708dSMark Brown info->regulator = regulator_register(&info->desc, &config); 400be0e2d3eSHaojian Zhuang if (IS_ERR(info->regulator)) { 401be0e2d3eSHaojian Zhuang dev_err(&pdev->dev, "failed to register regulator %s\n", 402be0e2d3eSHaojian Zhuang info->desc.name); 403be0e2d3eSHaojian Zhuang return PTR_ERR(info->regulator); 404be0e2d3eSHaojian Zhuang } 405be0e2d3eSHaojian Zhuang 406be0e2d3eSHaojian Zhuang platform_set_drvdata(pdev, info); 407be0e2d3eSHaojian Zhuang return 0; 408be0e2d3eSHaojian Zhuang } 409be0e2d3eSHaojian Zhuang 410be0e2d3eSHaojian Zhuang static int __devexit pm8607_regulator_remove(struct platform_device *pdev) 411be0e2d3eSHaojian Zhuang { 412be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = platform_get_drvdata(pdev); 413be0e2d3eSHaojian Zhuang 414192bbb95SHaojian Zhuang platform_set_drvdata(pdev, NULL); 415be0e2d3eSHaojian Zhuang regulator_unregister(info->regulator); 416be0e2d3eSHaojian Zhuang return 0; 417be0e2d3eSHaojian Zhuang } 418be0e2d3eSHaojian Zhuang 419192bbb95SHaojian Zhuang static struct platform_driver pm8607_regulator_driver = { 420192bbb95SHaojian Zhuang .driver = { 421192bbb95SHaojian Zhuang .name = "88pm860x-regulator", 422192bbb95SHaojian Zhuang .owner = THIS_MODULE, 423192bbb95SHaojian Zhuang }, 424192bbb95SHaojian Zhuang .probe = pm8607_regulator_probe, 425192bbb95SHaojian Zhuang .remove = __devexit_p(pm8607_regulator_remove), 426be0e2d3eSHaojian Zhuang }; 427be0e2d3eSHaojian Zhuang 428be0e2d3eSHaojian Zhuang static int __init pm8607_regulator_init(void) 429be0e2d3eSHaojian Zhuang { 430192bbb95SHaojian Zhuang return platform_driver_register(&pm8607_regulator_driver); 431be0e2d3eSHaojian Zhuang } 432be0e2d3eSHaojian Zhuang subsys_initcall(pm8607_regulator_init); 433be0e2d3eSHaojian Zhuang 434be0e2d3eSHaojian Zhuang static void __exit pm8607_regulator_exit(void) 435be0e2d3eSHaojian Zhuang { 436192bbb95SHaojian Zhuang platform_driver_unregister(&pm8607_regulator_driver); 437be0e2d3eSHaojian Zhuang } 438be0e2d3eSHaojian Zhuang module_exit(pm8607_regulator_exit); 439be0e2d3eSHaojian Zhuang 440be0e2d3eSHaojian Zhuang MODULE_LICENSE("GPL"); 441be0e2d3eSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); 442be0e2d3eSHaojian Zhuang MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC"); 443be0e2d3eSHaojian Zhuang MODULE_ALIAS("platform:88pm8607-regulator"); 444