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> 152e57d567SHaojian Zhuang #include <linux/of.h> 162e57d567SHaojian 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 slope_double; 34be0e2d3eSHaojian Zhuang }; 35be0e2d3eSHaojian Zhuang 369f79e9dbSHaojian Zhuang static const unsigned int BUCK1_table[] = { 379f79e9dbSHaojian Zhuang 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000, 389f79e9dbSHaojian Zhuang 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000, 399f79e9dbSHaojian Zhuang 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 409f79e9dbSHaojian Zhuang 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000, 419f79e9dbSHaojian Zhuang 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 429f79e9dbSHaojian Zhuang 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 439f79e9dbSHaojian Zhuang 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 449f79e9dbSHaojian Zhuang 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 459f79e9dbSHaojian Zhuang }; 46be0e2d3eSHaojian Zhuang 479f79e9dbSHaojian Zhuang static const unsigned int BUCK1_suspend_table[] = { 489f79e9dbSHaojian Zhuang 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 499f79e9dbSHaojian Zhuang 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 509f79e9dbSHaojian Zhuang 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 519f79e9dbSHaojian Zhuang 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 529f79e9dbSHaojian Zhuang 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000, 539f79e9dbSHaojian Zhuang 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 549f79e9dbSHaojian Zhuang 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 559f79e9dbSHaojian Zhuang 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000, 569f79e9dbSHaojian Zhuang }; 579f79e9dbSHaojian Zhuang 589f79e9dbSHaojian Zhuang static const unsigned int BUCK2_table[] = { 599f79e9dbSHaojian Zhuang 0, 50000, 100000, 150000, 200000, 250000, 300000, 350000, 609f79e9dbSHaojian Zhuang 400000, 450000, 500000, 550000, 600000, 650000, 700000, 750000, 619f79e9dbSHaojian Zhuang 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000, 629f79e9dbSHaojian Zhuang 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000, 639f79e9dbSHaojian Zhuang 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000, 649f79e9dbSHaojian Zhuang 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000, 659f79e9dbSHaojian Zhuang 2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000, 669f79e9dbSHaojian Zhuang 2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000, 679f79e9dbSHaojian Zhuang }; 689f79e9dbSHaojian Zhuang 699f79e9dbSHaojian Zhuang static const unsigned int BUCK2_suspend_table[] = { 709f79e9dbSHaojian Zhuang 0, 50000, 100000, 150000, 200000, 250000, 300000, 350000, 719f79e9dbSHaojian Zhuang 400000, 450000, 500000, 550000, 600000, 650000, 700000, 750000, 729f79e9dbSHaojian Zhuang 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000, 739f79e9dbSHaojian Zhuang 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000, 749f79e9dbSHaojian Zhuang 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000, 759f79e9dbSHaojian Zhuang 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000, 769f79e9dbSHaojian Zhuang 2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000, 779f79e9dbSHaojian Zhuang 2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000, 789f79e9dbSHaojian Zhuang }; 799f79e9dbSHaojian Zhuang 809f79e9dbSHaojian Zhuang static const unsigned int BUCK3_table[] = { 819f79e9dbSHaojian Zhuang 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 829f79e9dbSHaojian Zhuang 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 839f79e9dbSHaojian Zhuang 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 849f79e9dbSHaojian Zhuang 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 859f79e9dbSHaojian Zhuang 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000, 869f79e9dbSHaojian Zhuang 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 879f79e9dbSHaojian Zhuang 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 889f79e9dbSHaojian Zhuang 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000, 899f79e9dbSHaojian Zhuang }; 909f79e9dbSHaojian Zhuang 919f79e9dbSHaojian Zhuang static const unsigned int BUCK3_suspend_table[] = { 929f79e9dbSHaojian Zhuang 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 939f79e9dbSHaojian Zhuang 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 949f79e9dbSHaojian Zhuang 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 959f79e9dbSHaojian Zhuang 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 969f79e9dbSHaojian Zhuang 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000, 979f79e9dbSHaojian Zhuang 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 989f79e9dbSHaojian Zhuang 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 999f79e9dbSHaojian Zhuang 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000, 1009f79e9dbSHaojian Zhuang }; 1019f79e9dbSHaojian Zhuang 1029f79e9dbSHaojian Zhuang static const unsigned int LDO1_table[] = { 1039f79e9dbSHaojian Zhuang 1800000, 1200000, 2800000, 0, 1049f79e9dbSHaojian Zhuang }; 1059f79e9dbSHaojian Zhuang 1069f79e9dbSHaojian Zhuang static const unsigned int LDO1_suspend_table[] = { 1079f79e9dbSHaojian Zhuang 1800000, 1200000, 0, 0, 1089f79e9dbSHaojian Zhuang }; 1099f79e9dbSHaojian Zhuang 1109f79e9dbSHaojian Zhuang static const unsigned int LDO2_table[] = { 1119f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000, 1129f79e9dbSHaojian Zhuang }; 1139f79e9dbSHaojian Zhuang 1149f79e9dbSHaojian Zhuang static const unsigned int LDO2_suspend_table[] = { 1159f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1169f79e9dbSHaojian Zhuang }; 1179f79e9dbSHaojian Zhuang 1189f79e9dbSHaojian Zhuang static const unsigned int LDO3_table[] = { 1199f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000, 1209f79e9dbSHaojian Zhuang }; 1219f79e9dbSHaojian Zhuang 1229f79e9dbSHaojian Zhuang static const unsigned int LDO3_suspend_table[] = { 1239f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1249f79e9dbSHaojian Zhuang }; 1259f79e9dbSHaojian Zhuang 1269f79e9dbSHaojian Zhuang static const unsigned int LDO4_table[] = { 1279f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000, 1289f79e9dbSHaojian Zhuang }; 1299f79e9dbSHaojian Zhuang 1309f79e9dbSHaojian Zhuang static const unsigned int LDO4_suspend_table[] = { 1319f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000, 1329f79e9dbSHaojian Zhuang }; 1339f79e9dbSHaojian Zhuang 1349f79e9dbSHaojian Zhuang static const unsigned int LDO5_table[] = { 1359f79e9dbSHaojian Zhuang 2900000, 3000000, 3100000, 3300000, 1369f79e9dbSHaojian Zhuang }; 1379f79e9dbSHaojian Zhuang 1389f79e9dbSHaojian Zhuang static const unsigned int LDO5_suspend_table[] = { 1399f79e9dbSHaojian Zhuang 2900000, 0, 0, 0, 1409f79e9dbSHaojian Zhuang }; 1419f79e9dbSHaojian Zhuang 1429f79e9dbSHaojian Zhuang static const unsigned int LDO6_table[] = { 1439f79e9dbSHaojian Zhuang 1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000, 1449f79e9dbSHaojian Zhuang }; 1459f79e9dbSHaojian Zhuang 1469f79e9dbSHaojian Zhuang static const unsigned int LDO6_suspend_table[] = { 1479f79e9dbSHaojian Zhuang 1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000, 1489f79e9dbSHaojian Zhuang }; 1499f79e9dbSHaojian Zhuang 1509f79e9dbSHaojian Zhuang static const unsigned int LDO7_table[] = { 1519f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1529f79e9dbSHaojian Zhuang }; 1539f79e9dbSHaojian Zhuang 1549f79e9dbSHaojian Zhuang static const unsigned int LDO7_suspend_table[] = { 1559f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1569f79e9dbSHaojian Zhuang }; 1579f79e9dbSHaojian Zhuang 1589f79e9dbSHaojian Zhuang static const unsigned int LDO8_table[] = { 1599f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1609f79e9dbSHaojian Zhuang }; 1619f79e9dbSHaojian Zhuang 1629f79e9dbSHaojian Zhuang static const unsigned int LDO8_suspend_table[] = { 1639f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1649f79e9dbSHaojian Zhuang }; 1659f79e9dbSHaojian Zhuang 1669f79e9dbSHaojian Zhuang static const unsigned int LDO9_table[] = { 1679f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000, 1689f79e9dbSHaojian Zhuang }; 1699f79e9dbSHaojian Zhuang 1709f79e9dbSHaojian Zhuang static const unsigned int LDO9_suspend_table[] = { 1719f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1729f79e9dbSHaojian Zhuang }; 1739f79e9dbSHaojian Zhuang 1749f79e9dbSHaojian Zhuang static const unsigned int LDO10_table[] = { 1759f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000, 1769f79e9dbSHaojian Zhuang 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1779f79e9dbSHaojian Zhuang }; 1789f79e9dbSHaojian Zhuang 1799f79e9dbSHaojian Zhuang static const unsigned int LDO10_suspend_table[] = { 1809f79e9dbSHaojian Zhuang 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000, 1819f79e9dbSHaojian Zhuang 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1829f79e9dbSHaojian Zhuang }; 1839f79e9dbSHaojian Zhuang 1849f79e9dbSHaojian Zhuang static const unsigned int LDO12_table[] = { 1859f79e9dbSHaojian Zhuang 1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000, 1869f79e9dbSHaojian Zhuang 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1879f79e9dbSHaojian Zhuang }; 1889f79e9dbSHaojian Zhuang 1899f79e9dbSHaojian Zhuang static const unsigned int LDO12_suspend_table[] = { 1909f79e9dbSHaojian Zhuang 1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000, 1919f79e9dbSHaojian Zhuang 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1929f79e9dbSHaojian Zhuang }; 1939f79e9dbSHaojian Zhuang 1949f79e9dbSHaojian Zhuang static const unsigned int LDO13_table[] = { 1953380643bSJett.Zhou 1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0, 1969f79e9dbSHaojian Zhuang }; 1979f79e9dbSHaojian Zhuang 1989f79e9dbSHaojian Zhuang static const unsigned int LDO13_suspend_table[] = { 1999f79e9dbSHaojian Zhuang 0, 2009f79e9dbSHaojian Zhuang }; 2019f79e9dbSHaojian Zhuang 2029f79e9dbSHaojian Zhuang static const unsigned int LDO14_table[] = { 2039f79e9dbSHaojian Zhuang 1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000, 2049f79e9dbSHaojian Zhuang }; 2059f79e9dbSHaojian Zhuang 2069f79e9dbSHaojian Zhuang static const unsigned int LDO14_suspend_table[] = { 2079f79e9dbSHaojian Zhuang 1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000, 2089f79e9dbSHaojian Zhuang }; 209be0e2d3eSHaojian Zhuang 210be0e2d3eSHaojian Zhuang static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) 211be0e2d3eSHaojian Zhuang { 212be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 213be0e2d3eSHaojian Zhuang int ret = -EINVAL; 214be0e2d3eSHaojian Zhuang 21553b6949eSAxel Lin if (info->vol_table && (index < rdev->desc->n_voltages)) { 2169f79e9dbSHaojian Zhuang ret = info->vol_table[index]; 217be0e2d3eSHaojian Zhuang if (info->slope_double) 218be0e2d3eSHaojian Zhuang ret <<= 1; 219be0e2d3eSHaojian Zhuang } 220be0e2d3eSHaojian Zhuang return ret; 221be0e2d3eSHaojian Zhuang } 222be0e2d3eSHaojian Zhuang 223e7a7810aSJett.Zhou static int pm8606_preg_enable(struct regulator_dev *rdev) 224e7a7810aSJett.Zhou { 225e7a7810aSJett.Zhou struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 226e7a7810aSJett.Zhou 227e7a7810aSJett.Zhou return pm860x_set_bits(info->i2c, rdev->desc->enable_reg, 228e7a7810aSJett.Zhou 1 << rdev->desc->enable_mask, 0); 229e7a7810aSJett.Zhou } 230e7a7810aSJett.Zhou 231e7a7810aSJett.Zhou static int pm8606_preg_disable(struct regulator_dev *rdev) 232e7a7810aSJett.Zhou { 233e7a7810aSJett.Zhou struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 234e7a7810aSJett.Zhou 235e7a7810aSJett.Zhou return pm860x_set_bits(info->i2c, rdev->desc->enable_reg, 236e7a7810aSJett.Zhou 1 << rdev->desc->enable_mask, 237e7a7810aSJett.Zhou 1 << rdev->desc->enable_mask); 238e7a7810aSJett.Zhou } 239e7a7810aSJett.Zhou 240e7a7810aSJett.Zhou static int pm8606_preg_is_enabled(struct regulator_dev *rdev) 241e7a7810aSJett.Zhou { 242e7a7810aSJett.Zhou struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 243e7a7810aSJett.Zhou int ret; 244e7a7810aSJett.Zhou 245e7a7810aSJett.Zhou ret = pm860x_reg_read(info->i2c, rdev->desc->enable_reg); 246e7a7810aSJett.Zhou if (ret < 0) 247e7a7810aSJett.Zhou return ret; 248e7a7810aSJett.Zhou 249e7a7810aSJett.Zhou return !((unsigned char)ret & (1 << rdev->desc->enable_mask)); 250e7a7810aSJett.Zhou } 251e7a7810aSJett.Zhou 252be0e2d3eSHaojian Zhuang static struct regulator_ops pm8607_regulator_ops = { 253d3d7bcccSAxel Lin .list_voltage = pm8607_list_voltage, 254*c6f0a0efSAxel Lin .set_voltage_sel = regulator_set_voltage_sel_regmap, 255c006b21fSAxel Lin .get_voltage_sel = regulator_get_voltage_sel_regmap, 256ef26e0dbSAxel Lin .enable = regulator_enable_regmap, 257ef26e0dbSAxel Lin .disable = regulator_disable_regmap, 258ef26e0dbSAxel Lin .is_enabled = regulator_is_enabled_regmap, 259be0e2d3eSHaojian Zhuang }; 260be0e2d3eSHaojian Zhuang 261e7a7810aSJett.Zhou static struct regulator_ops pm8606_preg_ops = { 262e7a7810aSJett.Zhou .enable = pm8606_preg_enable, 263e7a7810aSJett.Zhou .disable = pm8606_preg_disable, 264e7a7810aSJett.Zhou .is_enabled = pm8606_preg_is_enabled, 265e7a7810aSJett.Zhou }; 266e7a7810aSJett.Zhou 267e7a7810aSJett.Zhou #define PM8606_PREG(ereg, ebit) \ 268e7a7810aSJett.Zhou { \ 269e7a7810aSJett.Zhou .desc = { \ 270e7a7810aSJett.Zhou .name = "PREG", \ 271e7a7810aSJett.Zhou .ops = &pm8606_preg_ops, \ 272e7a7810aSJett.Zhou .type = REGULATOR_CURRENT, \ 273e7a7810aSJett.Zhou .id = PM8606_ID_PREG, \ 274e7a7810aSJett.Zhou .owner = THIS_MODULE, \ 275e7a7810aSJett.Zhou .enable_reg = PM8606_##ereg, \ 276e7a7810aSJett.Zhou .enable_mask = (ebit), \ 277e7a7810aSJett.Zhou }, \ 278e7a7810aSJett.Zhou } 279e7a7810aSJett.Zhou 28053b6949eSAxel Lin #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \ 281be0e2d3eSHaojian Zhuang { \ 282be0e2d3eSHaojian Zhuang .desc = { \ 2839f79e9dbSHaojian Zhuang .name = #vreg, \ 284be0e2d3eSHaojian Zhuang .ops = &pm8607_regulator_ops, \ 285be0e2d3eSHaojian Zhuang .type = REGULATOR_VOLTAGE, \ 2869f79e9dbSHaojian Zhuang .id = PM8607_ID_##vreg, \ 287be0e2d3eSHaojian Zhuang .owner = THIS_MODULE, \ 28853b6949eSAxel Lin .n_voltages = ARRAY_SIZE(vreg##_table), \ 289c006b21fSAxel Lin .vsel_reg = PM8607_##vreg, \ 290c006b21fSAxel Lin .vsel_mask = ARRAY_SIZE(vreg##_table) - 1, \ 291*c6f0a0efSAxel Lin .apply_reg = PM8607_##ureg, \ 292*c6f0a0efSAxel Lin .apply_bit = (ubit), \ 293ef26e0dbSAxel Lin .enable_reg = PM8607_##ereg, \ 294ef26e0dbSAxel Lin .enable_mask = 1 << (ebit), \ 295be0e2d3eSHaojian Zhuang }, \ 296be0e2d3eSHaojian Zhuang .slope_double = (0), \ 2979f79e9dbSHaojian Zhuang .vol_table = (unsigned int *)&vreg##_table, \ 2989f79e9dbSHaojian Zhuang .vol_suspend = (unsigned int *)&vreg##_suspend_table, \ 299be0e2d3eSHaojian Zhuang } 300be0e2d3eSHaojian Zhuang 30153b6949eSAxel Lin #define PM8607_LDO(_id, vreg, shift, ereg, ebit) \ 302be0e2d3eSHaojian Zhuang { \ 303be0e2d3eSHaojian Zhuang .desc = { \ 304be0e2d3eSHaojian Zhuang .name = "LDO" #_id, \ 305be0e2d3eSHaojian Zhuang .ops = &pm8607_regulator_ops, \ 306be0e2d3eSHaojian Zhuang .type = REGULATOR_VOLTAGE, \ 307be0e2d3eSHaojian Zhuang .id = PM8607_ID_LDO##_id, \ 308be0e2d3eSHaojian Zhuang .owner = THIS_MODULE, \ 30953b6949eSAxel Lin .n_voltages = ARRAY_SIZE(LDO##_id##_table), \ 310c006b21fSAxel Lin .vsel_reg = PM8607_##vreg, \ 311c006b21fSAxel Lin .vsel_mask = (ARRAY_SIZE(LDO##_id##_table) - 1) << (shift), \ 312ef26e0dbSAxel Lin .enable_reg = PM8607_##ereg, \ 313ef26e0dbSAxel Lin .enable_mask = 1 << (ebit), \ 314be0e2d3eSHaojian Zhuang }, \ 315be0e2d3eSHaojian Zhuang .slope_double = (0), \ 3169f79e9dbSHaojian Zhuang .vol_table = (unsigned int *)&LDO##_id##_table, \ 3179f79e9dbSHaojian Zhuang .vol_suspend = (unsigned int *)&LDO##_id##_suspend_table, \ 318be0e2d3eSHaojian Zhuang } 319be0e2d3eSHaojian Zhuang 320be0e2d3eSHaojian Zhuang static struct pm8607_regulator_info pm8607_regulator_info[] = { 321*c6f0a0efSAxel Lin PM8607_DVC(BUCK1, GO, BIT(0), SUPPLIES_EN11, 0), 322*c6f0a0efSAxel Lin PM8607_DVC(BUCK2, GO, BIT(1), SUPPLIES_EN11, 1), 323*c6f0a0efSAxel Lin PM8607_DVC(BUCK3, GO, BIT(2), SUPPLIES_EN11, 2), 324be0e2d3eSHaojian Zhuang 32553b6949eSAxel Lin PM8607_LDO(1, LDO1, 0, SUPPLIES_EN11, 3), 32653b6949eSAxel Lin PM8607_LDO(2, LDO2, 0, SUPPLIES_EN11, 4), 32753b6949eSAxel Lin PM8607_LDO(3, LDO3, 0, SUPPLIES_EN11, 5), 32853b6949eSAxel Lin PM8607_LDO(4, LDO4, 0, SUPPLIES_EN11, 6), 32953b6949eSAxel Lin PM8607_LDO(5, LDO5, 0, SUPPLIES_EN11, 7), 33053b6949eSAxel Lin PM8607_LDO(6, LDO6, 0, SUPPLIES_EN12, 0), 33153b6949eSAxel Lin PM8607_LDO(7, LDO7, 0, SUPPLIES_EN12, 1), 33253b6949eSAxel Lin PM8607_LDO(8, LDO8, 0, SUPPLIES_EN12, 2), 33353b6949eSAxel Lin PM8607_LDO(9, LDO9, 0, SUPPLIES_EN12, 3), 33453b6949eSAxel Lin PM8607_LDO(10, LDO10, 0, SUPPLIES_EN12, 4), 33553b6949eSAxel Lin PM8607_LDO(12, LDO12, 0, SUPPLIES_EN12, 5), 33653b6949eSAxel Lin PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0), 33753b6949eSAxel Lin PM8607_LDO(14, LDO14, 0, SUPPLIES_EN12, 6), 338ff13e9e2SHaojian Zhuang }; 339e7a7810aSJett.Zhou 340ff13e9e2SHaojian Zhuang static struct pm8607_regulator_info pm8606_regulator_info[] = { 341e7a7810aSJett.Zhou PM8606_PREG(PREREGULATORB, 5), 342be0e2d3eSHaojian Zhuang }; 343be0e2d3eSHaojian Zhuang 3442e57d567SHaojian Zhuang #ifdef CONFIG_OF 3452e57d567SHaojian Zhuang static int pm8607_regulator_dt_init(struct platform_device *pdev, 3462e57d567SHaojian Zhuang struct pm8607_regulator_info *info, 3472e57d567SHaojian Zhuang struct regulator_config *config) 3482e57d567SHaojian Zhuang { 3492e57d567SHaojian Zhuang struct device_node *nproot, *np; 3502e57d567SHaojian Zhuang nproot = pdev->dev.parent->of_node; 3512e57d567SHaojian Zhuang if (!nproot) 3522e57d567SHaojian Zhuang return -ENODEV; 3532e57d567SHaojian Zhuang nproot = of_find_node_by_name(nproot, "regulators"); 3542e57d567SHaojian Zhuang if (!nproot) { 3552e57d567SHaojian Zhuang dev_err(&pdev->dev, "failed to find regulators node\n"); 3562e57d567SHaojian Zhuang return -ENODEV; 3572e57d567SHaojian Zhuang } 3582e57d567SHaojian Zhuang for_each_child_of_node(nproot, np) { 3592e57d567SHaojian Zhuang if (!of_node_cmp(np->name, info->desc.name)) { 3602e57d567SHaojian Zhuang config->init_data = 3612e57d567SHaojian Zhuang of_get_regulator_init_data(&pdev->dev, np); 3622e57d567SHaojian Zhuang config->of_node = np; 3632e57d567SHaojian Zhuang break; 3642e57d567SHaojian Zhuang } 3652e57d567SHaojian Zhuang } 3662e57d567SHaojian Zhuang return 0; 3672e57d567SHaojian Zhuang } 3682e57d567SHaojian Zhuang #else 3692e57d567SHaojian Zhuang #define pm8607_regulator_dt_init(x, y, z) (-1) 3702e57d567SHaojian Zhuang #endif 3712e57d567SHaojian Zhuang 372a5023574SBill Pemberton static int pm8607_regulator_probe(struct platform_device *pdev) 373be0e2d3eSHaojian Zhuang { 37453dbab7aSHaojian Zhuang struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); 375be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = NULL; 376586e1a17SHaojian Zhuang struct regulator_init_data *pdata = pdev->dev.platform_data; 377c172708dSMark Brown struct regulator_config config = { }; 378586e1a17SHaojian Zhuang struct resource *res; 37922aad001SHaojian Zhuang int i; 380be0e2d3eSHaojian Zhuang 38102367029SMark Brown res = platform_get_resource(pdev, IORESOURCE_REG, 0); 382ff13e9e2SHaojian Zhuang if (res) { 383ff13e9e2SHaojian Zhuang /* There're resources in 88PM8607 regulator driver */ 38422aad001SHaojian Zhuang for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { 38522aad001SHaojian Zhuang info = &pm8607_regulator_info[i]; 386a70abacbSHaojian Zhuang if (info->desc.vsel_reg == res->start) 38722aad001SHaojian Zhuang break; 38822aad001SHaojian Zhuang } 38999cd25ceSAxel Lin if (i == ARRAY_SIZE(pm8607_regulator_info)) { 39009969108SRandy Dunlap dev_err(&pdev->dev, "Failed to find regulator %llu\n", 39109969108SRandy Dunlap (unsigned long long)res->start); 392be0e2d3eSHaojian Zhuang return -EINVAL; 393be0e2d3eSHaojian Zhuang } 394ff13e9e2SHaojian Zhuang } else { 395ff13e9e2SHaojian Zhuang /* There's no resource in 88PM8606 PREG regulator driver */ 396ff13e9e2SHaojian Zhuang info = &pm8606_regulator_info[0]; 397ff13e9e2SHaojian Zhuang /* i is used to check regulator ID */ 398ff13e9e2SHaojian Zhuang i = -1; 399ff13e9e2SHaojian Zhuang } 40053dbab7aSHaojian Zhuang info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; 401e7a7810aSJett.Zhou info->i2c_8606 = (chip->id == CHIP_PM8607) ? chip->companion : 402e7a7810aSJett.Zhou chip->client; 403be0e2d3eSHaojian Zhuang info->chip = chip; 404be0e2d3eSHaojian Zhuang 40522aad001SHaojian Zhuang /* check DVC ramp slope double */ 406586e1a17SHaojian Zhuang if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double) 40722aad001SHaojian Zhuang info->slope_double = 1; 40822aad001SHaojian Zhuang 409c172708dSMark Brown config.dev = &pdev->dev; 410c172708dSMark Brown config.driver_data = info; 411c172708dSMark Brown 4122e57d567SHaojian Zhuang if (pm8607_regulator_dt_init(pdev, info, &config)) 4132e57d567SHaojian Zhuang if (pdata) 4142e57d567SHaojian Zhuang config.init_data = pdata; 4152e57d567SHaojian Zhuang 416ef26e0dbSAxel Lin if (chip->id == CHIP_PM8607) 417ef26e0dbSAxel Lin config.regmap = chip->regmap; 418ef26e0dbSAxel Lin else 419ef26e0dbSAxel Lin config.regmap = chip->regmap_companion; 420ef26e0dbSAxel Lin 421c172708dSMark Brown info->regulator = regulator_register(&info->desc, &config); 422be0e2d3eSHaojian Zhuang if (IS_ERR(info->regulator)) { 423be0e2d3eSHaojian Zhuang dev_err(&pdev->dev, "failed to register regulator %s\n", 424be0e2d3eSHaojian Zhuang info->desc.name); 425be0e2d3eSHaojian Zhuang return PTR_ERR(info->regulator); 426be0e2d3eSHaojian Zhuang } 427be0e2d3eSHaojian Zhuang 428be0e2d3eSHaojian Zhuang platform_set_drvdata(pdev, info); 429be0e2d3eSHaojian Zhuang return 0; 430be0e2d3eSHaojian Zhuang } 431be0e2d3eSHaojian Zhuang 4328dc995f5SBill Pemberton static int pm8607_regulator_remove(struct platform_device *pdev) 433be0e2d3eSHaojian Zhuang { 434be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = platform_get_drvdata(pdev); 435be0e2d3eSHaojian Zhuang 436192bbb95SHaojian Zhuang platform_set_drvdata(pdev, NULL); 437be0e2d3eSHaojian Zhuang regulator_unregister(info->regulator); 438be0e2d3eSHaojian Zhuang return 0; 439be0e2d3eSHaojian Zhuang } 440be0e2d3eSHaojian Zhuang 441e7a7810aSJett.Zhou static struct platform_device_id pm8607_regulator_driver_ids[] = { 442e7a7810aSJett.Zhou { 443e7a7810aSJett.Zhou .name = "88pm860x-regulator", 444e7a7810aSJett.Zhou .driver_data = 0, 445e7a7810aSJett.Zhou }, { 446e7a7810aSJett.Zhou .name = "88pm860x-preg", 447e7a7810aSJett.Zhou .driver_data = 0, 448e7a7810aSJett.Zhou }, 449e7a7810aSJett.Zhou { }, 450e7a7810aSJett.Zhou }; 451e7a7810aSJett.Zhou MODULE_DEVICE_TABLE(platform, pm8607_regulator_driver_ids); 452e7a7810aSJett.Zhou 453192bbb95SHaojian Zhuang static struct platform_driver pm8607_regulator_driver = { 454192bbb95SHaojian Zhuang .driver = { 455192bbb95SHaojian Zhuang .name = "88pm860x-regulator", 456192bbb95SHaojian Zhuang .owner = THIS_MODULE, 457192bbb95SHaojian Zhuang }, 458192bbb95SHaojian Zhuang .probe = pm8607_regulator_probe, 4595eb9f2b9SBill Pemberton .remove = pm8607_regulator_remove, 460e7a7810aSJett.Zhou .id_table = pm8607_regulator_driver_ids, 461be0e2d3eSHaojian Zhuang }; 462be0e2d3eSHaojian Zhuang 463be0e2d3eSHaojian Zhuang static int __init pm8607_regulator_init(void) 464be0e2d3eSHaojian Zhuang { 465192bbb95SHaojian Zhuang return platform_driver_register(&pm8607_regulator_driver); 466be0e2d3eSHaojian Zhuang } 467be0e2d3eSHaojian Zhuang subsys_initcall(pm8607_regulator_init); 468be0e2d3eSHaojian Zhuang 469be0e2d3eSHaojian Zhuang static void __exit pm8607_regulator_exit(void) 470be0e2d3eSHaojian Zhuang { 471192bbb95SHaojian Zhuang platform_driver_unregister(&pm8607_regulator_driver); 472be0e2d3eSHaojian Zhuang } 473be0e2d3eSHaojian Zhuang module_exit(pm8607_regulator_exit); 474be0e2d3eSHaojian Zhuang 475be0e2d3eSHaojian Zhuang MODULE_LICENSE("GPL"); 476be0e2d3eSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); 477be0e2d3eSHaojian Zhuang MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC"); 478be0e2d3eSHaojian Zhuang MODULE_ALIAS("platform:88pm8607-regulator"); 479