1809858cdSFabio Estevam // SPDX-License-Identifier: GPL-2.0+ 2809858cdSFabio Estevam // 3809858cdSFabio Estevam // Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. 4809858cdSFabio Estevam 53784b6d6SRobin Gong #include <linux/kernel.h> 63784b6d6SRobin Gong #include <linux/module.h> 73784b6d6SRobin Gong #include <linux/init.h> 83784b6d6SRobin Gong #include <linux/err.h> 93784b6d6SRobin Gong #include <linux/of.h> 103784b6d6SRobin Gong #include <linux/of_device.h> 113784b6d6SRobin Gong #include <linux/regulator/of_regulator.h> 123784b6d6SRobin Gong #include <linux/platform_device.h> 1302a1124dSDmitry Osipenko #include <linux/reboot.h> 143784b6d6SRobin Gong #include <linux/regulator/driver.h> 153784b6d6SRobin Gong #include <linux/regulator/machine.h> 163784b6d6SRobin Gong #include <linux/regulator/pfuze100.h> 173784b6d6SRobin Gong #include <linux/i2c.h> 183784b6d6SRobin Gong #include <linux/slab.h> 193784b6d6SRobin Gong #include <linux/regmap.h> 203784b6d6SRobin Gong 219d2fd4f0SMarco Felsch #define PFUZE_FLAG_DISABLE_SW BIT(1) 229d2fd4f0SMarco Felsch 233784b6d6SRobin Gong #define PFUZE_NUMREGS 128 243784b6d6SRobin Gong #define PFUZE100_VOL_OFFSET 0 253784b6d6SRobin Gong #define PFUZE100_STANDBY_OFFSET 1 263784b6d6SRobin Gong #define PFUZE100_MODE_OFFSET 3 273784b6d6SRobin Gong #define PFUZE100_CONF_OFFSET 4 283784b6d6SRobin Gong 293784b6d6SRobin Gong #define PFUZE100_DEVICEID 0x0 303784b6d6SRobin Gong #define PFUZE100_REVID 0x3 31a1b6fa85SAxel Lin #define PFUZE100_FABID 0x4 323784b6d6SRobin Gong 33c6182ac9SGeorge McCollister #define PFUZE100_COINVOL 0x1a 343784b6d6SRobin Gong #define PFUZE100_SW1ABVOL 0x20 35c29daffaSOleksij Rempel #define PFUZE100_SW1ABMODE 0x23 363784b6d6SRobin Gong #define PFUZE100_SW1CVOL 0x2e 37c29daffaSOleksij Rempel #define PFUZE100_SW1CMODE 0x31 383784b6d6SRobin Gong #define PFUZE100_SW2VOL 0x35 39c29daffaSOleksij Rempel #define PFUZE100_SW2MODE 0x38 403784b6d6SRobin Gong #define PFUZE100_SW3AVOL 0x3c 41c29daffaSOleksij Rempel #define PFUZE100_SW3AMODE 0x3f 423784b6d6SRobin Gong #define PFUZE100_SW3BVOL 0x43 43c29daffaSOleksij Rempel #define PFUZE100_SW3BMODE 0x46 443784b6d6SRobin Gong #define PFUZE100_SW4VOL 0x4a 45c29daffaSOleksij Rempel #define PFUZE100_SW4MODE 0x4d 463784b6d6SRobin Gong #define PFUZE100_SWBSTCON1 0x66 473784b6d6SRobin Gong #define PFUZE100_VREFDDRCON 0x6a 483784b6d6SRobin Gong #define PFUZE100_VSNVSVOL 0x6b 493784b6d6SRobin Gong #define PFUZE100_VGEN1VOL 0x6c 503784b6d6SRobin Gong #define PFUZE100_VGEN2VOL 0x6d 513784b6d6SRobin Gong #define PFUZE100_VGEN3VOL 0x6e 523784b6d6SRobin Gong #define PFUZE100_VGEN4VOL 0x6f 533784b6d6SRobin Gong #define PFUZE100_VGEN5VOL 0x70 543784b6d6SRobin Gong #define PFUZE100_VGEN6VOL 0x71 553784b6d6SRobin Gong 56c29daffaSOleksij Rempel #define PFUZE100_SWxMODE_MASK 0xf 57c29daffaSOleksij Rempel #define PFUZE100_SWxMODE_APS_APS 0x8 58c29daffaSOleksij Rempel #define PFUZE100_SWxMODE_APS_OFF 0x4 59c29daffaSOleksij Rempel 60c29daffaSOleksij Rempel #define PFUZE100_VGENxLPWR BIT(6) 61c29daffaSOleksij Rempel #define PFUZE100_VGENxSTBY BIT(5) 62c29daffaSOleksij Rempel 63297101abSStefan Wahren enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3, PFUZE3001 = 0x31, }; 64f2518480SRobin Gong 653784b6d6SRobin Gong struct pfuze_regulator { 663784b6d6SRobin Gong struct regulator_desc desc; 673784b6d6SRobin Gong unsigned char stby_reg; 683784b6d6SRobin Gong unsigned char stby_mask; 699d2fd4f0SMarco Felsch bool sw_reg; 703784b6d6SRobin Gong }; 713784b6d6SRobin Gong 723784b6d6SRobin Gong struct pfuze_chip { 73f2518480SRobin Gong int chip_id; 749d2fd4f0SMarco Felsch int flags; 753784b6d6SRobin Gong struct regmap *regmap; 763784b6d6SRobin Gong struct device *dev; 773784b6d6SRobin Gong struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR]; 783784b6d6SRobin Gong struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR]; 7912425654SFabio Estevam struct pfuze_regulator *pfuze_regulators; 803784b6d6SRobin Gong }; 813784b6d6SRobin Gong 823784b6d6SRobin Gong static const int pfuze100_swbst[] = { 833784b6d6SRobin Gong 5000000, 5050000, 5100000, 5150000, 843784b6d6SRobin Gong }; 853784b6d6SRobin Gong 863784b6d6SRobin Gong static const int pfuze100_vsnvs[] = { 873784b6d6SRobin Gong 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000, 883784b6d6SRobin Gong }; 893784b6d6SRobin Gong 90c6182ac9SGeorge McCollister static const int pfuze100_coin[] = { 91c6182ac9SGeorge McCollister 2500000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000, 92c6182ac9SGeorge McCollister }; 93c6182ac9SGeorge McCollister 941dced996SAnson Huang static const int pfuze3000_sw1a[] = { 951dced996SAnson Huang 700000, 725000, 750000, 775000, 800000, 825000, 850000, 875000, 961dced996SAnson Huang 900000, 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 971dced996SAnson Huang 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 981dced996SAnson Huang 1300000, 1325000, 1350000, 1375000, 1400000, 1425000, 1800000, 3300000, 991dced996SAnson Huang }; 1001dced996SAnson Huang 101e5a7a72cSRobin Gong static const int pfuze3000_sw2lo[] = { 102e5a7a72cSRobin Gong 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 103e5a7a72cSRobin Gong }; 104e5a7a72cSRobin Gong 105e5a7a72cSRobin Gong static const int pfuze3000_sw2hi[] = { 106e5a7a72cSRobin Gong 2500000, 2800000, 2850000, 3000000, 3100000, 3150000, 3200000, 3300000, 107e5a7a72cSRobin Gong }; 108e5a7a72cSRobin Gong 1093784b6d6SRobin Gong static const struct of_device_id pfuze_dt_ids[] = { 110f2518480SRobin Gong { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100}, 111f2518480SRobin Gong { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200}, 112e5a7a72cSRobin Gong { .compatible = "fsl,pfuze3000", .data = (void *)PFUZE3000}, 113297101abSStefan Wahren { .compatible = "fsl,pfuze3001", .data = (void *)PFUZE3001}, 114e6c4c337SAxel Lin { } 1153784b6d6SRobin Gong }; 1163784b6d6SRobin Gong MODULE_DEVICE_TABLE(of, pfuze_dt_ids); 1173784b6d6SRobin Gong 1183784b6d6SRobin Gong static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) 1193784b6d6SRobin Gong { 1203784b6d6SRobin Gong struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev); 121d55efa4dSThiago Farina int id = rdev_get_id(rdev); 122297101abSStefan Wahren bool reg_has_ramp_delay; 123a7503a9dSRobin Gong unsigned int ramp_bits = 0; 1243784b6d6SRobin Gong int ret; 1253784b6d6SRobin Gong 126297101abSStefan Wahren switch (pfuze100->chip_id) { 127297101abSStefan Wahren case PFUZE3001: 128297101abSStefan Wahren /* no dynamic voltage scaling for PF3001 */ 129297101abSStefan Wahren reg_has_ramp_delay = false; 130297101abSStefan Wahren break; 131297101abSStefan Wahren case PFUZE3000: 132297101abSStefan Wahren reg_has_ramp_delay = (id < PFUZE3000_SWBST); 133297101abSStefan Wahren break; 134297101abSStefan Wahren case PFUZE200: 135297101abSStefan Wahren reg_has_ramp_delay = (id < PFUZE200_SWBST); 136297101abSStefan Wahren break; 137297101abSStefan Wahren case PFUZE100: 138297101abSStefan Wahren default: 139297101abSStefan Wahren reg_has_ramp_delay = (id < PFUZE100_SWBST); 140297101abSStefan Wahren break; 141297101abSStefan Wahren } 142297101abSStefan Wahren 143297101abSStefan Wahren if (reg_has_ramp_delay) { 144a7503a9dSRobin Gong if (ramp_delay > 0) { 145e5656669SAxel Lin ramp_delay = 12500 / ramp_delay; 1463784b6d6SRobin Gong ramp_bits = (ramp_delay >> 1) - (ramp_delay >> 3); 147a7503a9dSRobin Gong } 148a7503a9dSRobin Gong 149e5656669SAxel Lin ret = regmap_update_bits(pfuze100->regmap, 150e5656669SAxel Lin rdev->desc->vsel_reg + 4, 151e5656669SAxel Lin 0xc0, ramp_bits << 6); 1523784b6d6SRobin Gong if (ret < 0) 1533784b6d6SRobin Gong dev_err(pfuze100->dev, "ramp failed, err %d\n", ret); 154297101abSStefan Wahren } else { 1553784b6d6SRobin Gong ret = -EACCES; 156297101abSStefan Wahren } 1573784b6d6SRobin Gong 1583784b6d6SRobin Gong return ret; 1593784b6d6SRobin Gong } 1603784b6d6SRobin Gong 161e5053853SBhumika Goyal static const struct regulator_ops pfuze100_ldo_regulator_ops = { 1623784b6d6SRobin Gong .enable = regulator_enable_regmap, 1633784b6d6SRobin Gong .disable = regulator_disable_regmap, 1643784b6d6SRobin Gong .is_enabled = regulator_is_enabled_regmap, 1653784b6d6SRobin Gong .list_voltage = regulator_list_voltage_linear, 1663784b6d6SRobin Gong .set_voltage_sel = regulator_set_voltage_sel_regmap, 1673784b6d6SRobin Gong .get_voltage_sel = regulator_get_voltage_sel_regmap, 1683784b6d6SRobin Gong }; 1693784b6d6SRobin Gong 170e5053853SBhumika Goyal static const struct regulator_ops pfuze100_fixed_regulator_ops = { 171ab3ca774SAxel Lin .enable = regulator_enable_regmap, 172ab3ca774SAxel Lin .disable = regulator_disable_regmap, 173ab3ca774SAxel Lin .is_enabled = regulator_is_enabled_regmap, 1743784b6d6SRobin Gong .list_voltage = regulator_list_voltage_linear, 1753784b6d6SRobin Gong }; 1763784b6d6SRobin Gong 177e5053853SBhumika Goyal static const struct regulator_ops pfuze100_sw_regulator_ops = { 1783784b6d6SRobin Gong .list_voltage = regulator_list_voltage_linear, 1793784b6d6SRobin Gong .set_voltage_sel = regulator_set_voltage_sel_regmap, 1803784b6d6SRobin Gong .get_voltage_sel = regulator_get_voltage_sel_regmap, 1813784b6d6SRobin Gong .set_voltage_time_sel = regulator_set_voltage_time_sel, 1823784b6d6SRobin Gong .set_ramp_delay = pfuze100_set_ramp_delay, 1833784b6d6SRobin Gong }; 1843784b6d6SRobin Gong 1859d2fd4f0SMarco Felsch static const struct regulator_ops pfuze100_sw_disable_regulator_ops = { 1869d2fd4f0SMarco Felsch .enable = regulator_enable_regmap, 1879d2fd4f0SMarco Felsch .disable = regulator_disable_regmap, 1889d2fd4f0SMarco Felsch .is_enabled = regulator_is_enabled_regmap, 1899d2fd4f0SMarco Felsch .list_voltage = regulator_list_voltage_linear, 1909d2fd4f0SMarco Felsch .set_voltage_sel = regulator_set_voltage_sel_regmap, 1919d2fd4f0SMarco Felsch .get_voltage_sel = regulator_get_voltage_sel_regmap, 1929d2fd4f0SMarco Felsch .set_voltage_time_sel = regulator_set_voltage_time_sel, 1939d2fd4f0SMarco Felsch .set_ramp_delay = pfuze100_set_ramp_delay, 1949d2fd4f0SMarco Felsch }; 1959d2fd4f0SMarco Felsch 196e5053853SBhumika Goyal static const struct regulator_ops pfuze100_swb_regulator_ops = { 197a6dcf978SSean Cross .enable = regulator_enable_regmap, 198a6dcf978SSean Cross .disable = regulator_disable_regmap, 1990b01fd3dSAnson Huang .is_enabled = regulator_is_enabled_regmap, 2003784b6d6SRobin Gong .list_voltage = regulator_list_voltage_table, 2012e04cc41SAxel Lin .map_voltage = regulator_map_voltage_ascend, 2023784b6d6SRobin Gong .set_voltage_sel = regulator_set_voltage_sel_regmap, 2033784b6d6SRobin Gong .get_voltage_sel = regulator_get_voltage_sel_regmap, 2043784b6d6SRobin Gong 2053784b6d6SRobin Gong }; 2063784b6d6SRobin Gong 2076f1cf525SRobin Gong static const struct regulator_ops pfuze3000_sw_regulator_ops = { 2086f1cf525SRobin Gong .enable = regulator_enable_regmap, 2096f1cf525SRobin Gong .disable = regulator_disable_regmap, 2106f1cf525SRobin Gong .is_enabled = regulator_is_enabled_regmap, 2116f1cf525SRobin Gong .list_voltage = regulator_list_voltage_table, 2126f1cf525SRobin Gong .map_voltage = regulator_map_voltage_ascend, 2136f1cf525SRobin Gong .set_voltage_sel = regulator_set_voltage_sel_regmap, 2146f1cf525SRobin Gong .get_voltage_sel = regulator_get_voltage_sel_regmap, 2156f1cf525SRobin Gong .set_voltage_time_sel = regulator_set_voltage_time_sel, 2166f1cf525SRobin Gong .set_ramp_delay = pfuze100_set_ramp_delay, 2176f1cf525SRobin Gong 2186f1cf525SRobin Gong }; 2196f1cf525SRobin Gong 220f2518480SRobin Gong #define PFUZE100_FIXED_REG(_chip, _name, base, voltage) \ 221f2518480SRobin Gong [_chip ## _ ## _name] = { \ 2223784b6d6SRobin Gong .desc = { \ 2233784b6d6SRobin Gong .name = #_name, \ 2243784b6d6SRobin Gong .n_voltages = 1, \ 2253784b6d6SRobin Gong .ops = &pfuze100_fixed_regulator_ops, \ 2263784b6d6SRobin Gong .type = REGULATOR_VOLTAGE, \ 227f2518480SRobin Gong .id = _chip ## _ ## _name, \ 2283784b6d6SRobin Gong .owner = THIS_MODULE, \ 2293784b6d6SRobin Gong .min_uV = (voltage), \ 2303784b6d6SRobin Gong .enable_reg = (base), \ 2313784b6d6SRobin Gong .enable_mask = 0x10, \ 2323784b6d6SRobin Gong }, \ 2333784b6d6SRobin Gong } 2343784b6d6SRobin Gong 235f2518480SRobin Gong #define PFUZE100_SW_REG(_chip, _name, base, min, max, step) \ 236f2518480SRobin Gong [_chip ## _ ## _name] = { \ 2373784b6d6SRobin Gong .desc = { \ 2383784b6d6SRobin Gong .name = #_name,\ 2393784b6d6SRobin Gong .n_voltages = ((max) - (min)) / (step) + 1, \ 2403784b6d6SRobin Gong .ops = &pfuze100_sw_regulator_ops, \ 2413784b6d6SRobin Gong .type = REGULATOR_VOLTAGE, \ 242f2518480SRobin Gong .id = _chip ## _ ## _name, \ 2433784b6d6SRobin Gong .owner = THIS_MODULE, \ 2443784b6d6SRobin Gong .min_uV = (min), \ 2453784b6d6SRobin Gong .uV_step = (step), \ 2463784b6d6SRobin Gong .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ 2473784b6d6SRobin Gong .vsel_mask = 0x3f, \ 2489d2fd4f0SMarco Felsch .enable_reg = (base) + PFUZE100_MODE_OFFSET, \ 2499d2fd4f0SMarco Felsch .enable_mask = 0xf, \ 2503784b6d6SRobin Gong }, \ 2513784b6d6SRobin Gong .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ 2523784b6d6SRobin Gong .stby_mask = 0x3f, \ 2539d2fd4f0SMarco Felsch .sw_reg = true, \ 2543784b6d6SRobin Gong } 2553784b6d6SRobin Gong 256f2518480SRobin Gong #define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages) \ 257f2518480SRobin Gong [_chip ## _ ## _name] = { \ 2583784b6d6SRobin Gong .desc = { \ 2593784b6d6SRobin Gong .name = #_name, \ 2603784b6d6SRobin Gong .n_voltages = ARRAY_SIZE(voltages), \ 2613784b6d6SRobin Gong .ops = &pfuze100_swb_regulator_ops, \ 2623784b6d6SRobin Gong .type = REGULATOR_VOLTAGE, \ 263f2518480SRobin Gong .id = _chip ## _ ## _name, \ 2643784b6d6SRobin Gong .owner = THIS_MODULE, \ 2653784b6d6SRobin Gong .volt_table = voltages, \ 2663784b6d6SRobin Gong .vsel_reg = (base), \ 2673784b6d6SRobin Gong .vsel_mask = (mask), \ 268a6dcf978SSean Cross .enable_reg = (base), \ 269a6dcf978SSean Cross .enable_mask = 0x48, \ 2703784b6d6SRobin Gong }, \ 2713784b6d6SRobin Gong } 2723784b6d6SRobin Gong 273f2518480SRobin Gong #define PFUZE100_VGEN_REG(_chip, _name, base, min, max, step) \ 274f2518480SRobin Gong [_chip ## _ ## _name] = { \ 2753784b6d6SRobin Gong .desc = { \ 2763784b6d6SRobin Gong .name = #_name, \ 2773784b6d6SRobin Gong .n_voltages = ((max) - (min)) / (step) + 1, \ 2783784b6d6SRobin Gong .ops = &pfuze100_ldo_regulator_ops, \ 2793784b6d6SRobin Gong .type = REGULATOR_VOLTAGE, \ 280f2518480SRobin Gong .id = _chip ## _ ## _name, \ 2813784b6d6SRobin Gong .owner = THIS_MODULE, \ 2823784b6d6SRobin Gong .min_uV = (min), \ 2833784b6d6SRobin Gong .uV_step = (step), \ 2843784b6d6SRobin Gong .vsel_reg = (base), \ 2853784b6d6SRobin Gong .vsel_mask = 0xf, \ 2863784b6d6SRobin Gong .enable_reg = (base), \ 2873784b6d6SRobin Gong .enable_mask = 0x10, \ 2883784b6d6SRobin Gong }, \ 2893784b6d6SRobin Gong .stby_reg = (base), \ 2903784b6d6SRobin Gong .stby_mask = 0x20, \ 2913784b6d6SRobin Gong } 2923784b6d6SRobin Gong 293c6182ac9SGeorge McCollister #define PFUZE100_COIN_REG(_chip, _name, base, mask, voltages) \ 294c6182ac9SGeorge McCollister [_chip ## _ ## _name] = { \ 295c6182ac9SGeorge McCollister .desc = { \ 296c6182ac9SGeorge McCollister .name = #_name, \ 297c6182ac9SGeorge McCollister .n_voltages = ARRAY_SIZE(voltages), \ 298c6182ac9SGeorge McCollister .ops = &pfuze100_swb_regulator_ops, \ 299c6182ac9SGeorge McCollister .type = REGULATOR_VOLTAGE, \ 300c6182ac9SGeorge McCollister .id = _chip ## _ ## _name, \ 301c6182ac9SGeorge McCollister .owner = THIS_MODULE, \ 302c6182ac9SGeorge McCollister .volt_table = voltages, \ 303c6182ac9SGeorge McCollister .vsel_reg = (base), \ 304c6182ac9SGeorge McCollister .vsel_mask = (mask), \ 305c6182ac9SGeorge McCollister .enable_reg = (base), \ 306c6182ac9SGeorge McCollister .enable_mask = 0x8, \ 307c6182ac9SGeorge McCollister }, \ 308c6182ac9SGeorge McCollister } 309c6182ac9SGeorge McCollister 310e5a7a72cSRobin Gong #define PFUZE3000_VCC_REG(_chip, _name, base, min, max, step) { \ 311e5a7a72cSRobin Gong .desc = { \ 312e5a7a72cSRobin Gong .name = #_name, \ 313e5a7a72cSRobin Gong .n_voltages = ((max) - (min)) / (step) + 1, \ 314e5a7a72cSRobin Gong .ops = &pfuze100_ldo_regulator_ops, \ 315e5a7a72cSRobin Gong .type = REGULATOR_VOLTAGE, \ 316e5a7a72cSRobin Gong .id = _chip ## _ ## _name, \ 317e5a7a72cSRobin Gong .owner = THIS_MODULE, \ 318e5a7a72cSRobin Gong .min_uV = (min), \ 319e5a7a72cSRobin Gong .uV_step = (step), \ 320e5a7a72cSRobin Gong .vsel_reg = (base), \ 321e5a7a72cSRobin Gong .vsel_mask = 0x3, \ 322e5a7a72cSRobin Gong .enable_reg = (base), \ 323e5a7a72cSRobin Gong .enable_mask = 0x10, \ 324e5a7a72cSRobin Gong }, \ 325e5a7a72cSRobin Gong .stby_reg = (base), \ 326e5a7a72cSRobin Gong .stby_mask = 0x20, \ 327e5a7a72cSRobin Gong } 328e5a7a72cSRobin Gong 3296f1cf525SRobin Gong /* No linar case for the some switches of PFUZE3000 */ 3306f1cf525SRobin Gong #define PFUZE3000_SW_REG(_chip, _name, base, mask, voltages) \ 3316f1cf525SRobin Gong [_chip ## _ ## _name] = { \ 332e5a7a72cSRobin Gong .desc = { \ 333e5a7a72cSRobin Gong .name = #_name, \ 3346f1cf525SRobin Gong .n_voltages = ARRAY_SIZE(voltages), \ 3356f1cf525SRobin Gong .ops = &pfuze3000_sw_regulator_ops, \ 336e5a7a72cSRobin Gong .type = REGULATOR_VOLTAGE, \ 337e5a7a72cSRobin Gong .id = _chip ## _ ## _name, \ 338e5a7a72cSRobin Gong .owner = THIS_MODULE, \ 3396f1cf525SRobin Gong .volt_table = voltages, \ 340e5a7a72cSRobin Gong .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ 3416f1cf525SRobin Gong .vsel_mask = (mask), \ 3426f1cf525SRobin Gong .enable_reg = (base) + PFUZE100_MODE_OFFSET, \ 3436f1cf525SRobin Gong .enable_mask = 0xf, \ 3446f1cf525SRobin Gong .enable_val = 0x8, \ 3456f1cf525SRobin Gong .enable_time = 500, \ 346e5a7a72cSRobin Gong }, \ 347e5a7a72cSRobin Gong .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ 3486f1cf525SRobin Gong .stby_mask = (mask), \ 3496f1cf525SRobin Gong .sw_reg = true, \ 350e5a7a72cSRobin Gong } 351e5a7a72cSRobin Gong 352e5a7a72cSRobin Gong #define PFUZE3000_SW3_REG(_chip, _name, base, min, max, step) { \ 353e5a7a72cSRobin Gong .desc = { \ 354e5a7a72cSRobin Gong .name = #_name,\ 355e5a7a72cSRobin Gong .n_voltages = ((max) - (min)) / (step) + 1, \ 356e5a7a72cSRobin Gong .ops = &pfuze100_sw_regulator_ops, \ 357e5a7a72cSRobin Gong .type = REGULATOR_VOLTAGE, \ 358e5a7a72cSRobin Gong .id = _chip ## _ ## _name, \ 359e5a7a72cSRobin Gong .owner = THIS_MODULE, \ 360e5a7a72cSRobin Gong .min_uV = (min), \ 361e5a7a72cSRobin Gong .uV_step = (step), \ 362e5a7a72cSRobin Gong .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ 363e5a7a72cSRobin Gong .vsel_mask = 0xf, \ 364e5a7a72cSRobin Gong }, \ 365e5a7a72cSRobin Gong .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ 366e5a7a72cSRobin Gong .stby_mask = 0xf, \ 367e5a7a72cSRobin Gong } 368e5a7a72cSRobin Gong 369f2518480SRobin Gong /* PFUZE100 */ 3703784b6d6SRobin Gong static struct pfuze_regulator pfuze100_regulators[] = { 371f2518480SRobin Gong PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), 372f2518480SRobin Gong PFUZE100_SW_REG(PFUZE100, SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000), 373f2518480SRobin Gong PFUZE100_SW_REG(PFUZE100, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), 374f2518480SRobin Gong PFUZE100_SW_REG(PFUZE100, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), 375f2518480SRobin Gong PFUZE100_SW_REG(PFUZE100, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), 376f2518480SRobin Gong PFUZE100_SW_REG(PFUZE100, SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000), 377f2518480SRobin Gong PFUZE100_SWB_REG(PFUZE100, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), 378f2518480SRobin Gong PFUZE100_SWB_REG(PFUZE100, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), 379f2518480SRobin Gong PFUZE100_FIXED_REG(PFUZE100, VREFDDR, PFUZE100_VREFDDRCON, 750000), 380f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE100, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), 381f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE100, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), 382f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE100, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), 383f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), 384f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), 385f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), 38661d0de05SAdam Ford PFUZE100_COIN_REG(PFUZE100, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin), 3873784b6d6SRobin Gong }; 3883784b6d6SRobin Gong 389f2518480SRobin Gong static struct pfuze_regulator pfuze200_regulators[] = { 390f2518480SRobin Gong PFUZE100_SW_REG(PFUZE200, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), 391f2518480SRobin Gong PFUZE100_SW_REG(PFUZE200, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), 392f2518480SRobin Gong PFUZE100_SW_REG(PFUZE200, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), 393f2518480SRobin Gong PFUZE100_SW_REG(PFUZE200, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), 394f2518480SRobin Gong PFUZE100_SWB_REG(PFUZE200, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), 395f2518480SRobin Gong PFUZE100_SWB_REG(PFUZE200, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), 396f2518480SRobin Gong PFUZE100_FIXED_REG(PFUZE200, VREFDDR, PFUZE100_VREFDDRCON, 750000), 397f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE200, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), 398f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE200, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), 399f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE200, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), 400f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE200, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), 401f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE200, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), 402f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), 403c6182ac9SGeorge McCollister PFUZE100_COIN_REG(PFUZE200, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin), 404f2518480SRobin Gong }; 405f2518480SRobin Gong 406e5a7a72cSRobin Gong static struct pfuze_regulator pfuze3000_regulators[] = { 4076f1cf525SRobin Gong PFUZE3000_SW_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a), 408e5a7a72cSRobin Gong PFUZE100_SW_REG(PFUZE3000, SW1B, PFUZE100_SW1CVOL, 700000, 1475000, 25000), 4096f1cf525SRobin Gong PFUZE3000_SW_REG(PFUZE3000, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo), 410e5a7a72cSRobin Gong PFUZE3000_SW3_REG(PFUZE3000, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000), 411e5a7a72cSRobin Gong PFUZE100_SWB_REG(PFUZE3000, SWBST, PFUZE100_SWBSTCON1, 0x3, pfuze100_swbst), 412e5a7a72cSRobin Gong PFUZE100_SWB_REG(PFUZE3000, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), 413e5a7a72cSRobin Gong PFUZE100_FIXED_REG(PFUZE3000, VREFDDR, PFUZE100_VREFDDRCON, 750000), 414e5a7a72cSRobin Gong PFUZE100_VGEN_REG(PFUZE3000, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000), 415e5a7a72cSRobin Gong PFUZE100_VGEN_REG(PFUZE3000, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), 416e5a7a72cSRobin Gong PFUZE3000_VCC_REG(PFUZE3000, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000), 417e5a7a72cSRobin Gong PFUZE3000_VCC_REG(PFUZE3000, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000), 418e5a7a72cSRobin Gong PFUZE100_VGEN_REG(PFUZE3000, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), 419e5a7a72cSRobin Gong PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), 420e5a7a72cSRobin Gong }; 421e5a7a72cSRobin Gong 422297101abSStefan Wahren static struct pfuze_regulator pfuze3001_regulators[] = { 4236f1cf525SRobin Gong PFUZE3000_SW_REG(PFUZE3001, SW1, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a), 4246f1cf525SRobin Gong PFUZE3000_SW_REG(PFUZE3001, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo), 425297101abSStefan Wahren PFUZE3000_SW3_REG(PFUZE3001, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000), 426297101abSStefan Wahren PFUZE100_SWB_REG(PFUZE3001, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), 427297101abSStefan Wahren PFUZE100_VGEN_REG(PFUZE3001, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000), 428297101abSStefan Wahren PFUZE100_VGEN_REG(PFUZE3001, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), 429297101abSStefan Wahren PFUZE3000_VCC_REG(PFUZE3001, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000), 430297101abSStefan Wahren PFUZE3000_VCC_REG(PFUZE3001, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000), 431297101abSStefan Wahren PFUZE100_VGEN_REG(PFUZE3001, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), 432297101abSStefan Wahren PFUZE100_VGEN_REG(PFUZE3001, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), 433297101abSStefan Wahren }; 434297101abSStefan Wahren 435f2518480SRobin Gong /* PFUZE100 */ 4363784b6d6SRobin Gong static struct of_regulator_match pfuze100_matches[] = { 4373784b6d6SRobin Gong { .name = "sw1ab", }, 4383784b6d6SRobin Gong { .name = "sw1c", }, 4393784b6d6SRobin Gong { .name = "sw2", }, 4403784b6d6SRobin Gong { .name = "sw3a", }, 4413784b6d6SRobin Gong { .name = "sw3b", }, 4423784b6d6SRobin Gong { .name = "sw4", }, 4433784b6d6SRobin Gong { .name = "swbst", }, 4443784b6d6SRobin Gong { .name = "vsnvs", }, 4453784b6d6SRobin Gong { .name = "vrefddr", }, 4463784b6d6SRobin Gong { .name = "vgen1", }, 4473784b6d6SRobin Gong { .name = "vgen2", }, 4483784b6d6SRobin Gong { .name = "vgen3", }, 4493784b6d6SRobin Gong { .name = "vgen4", }, 4503784b6d6SRobin Gong { .name = "vgen5", }, 4513784b6d6SRobin Gong { .name = "vgen6", }, 45261d0de05SAdam Ford { .name = "coin", }, 4533784b6d6SRobin Gong }; 4543784b6d6SRobin Gong 455f2518480SRobin Gong /* PFUZE200 */ 456f2518480SRobin Gong static struct of_regulator_match pfuze200_matches[] = { 457f2518480SRobin Gong 458f2518480SRobin Gong { .name = "sw1ab", }, 459f2518480SRobin Gong { .name = "sw2", }, 460f2518480SRobin Gong { .name = "sw3a", }, 461f2518480SRobin Gong { .name = "sw3b", }, 462f2518480SRobin Gong { .name = "swbst", }, 463f2518480SRobin Gong { .name = "vsnvs", }, 464f2518480SRobin Gong { .name = "vrefddr", }, 465f2518480SRobin Gong { .name = "vgen1", }, 466f2518480SRobin Gong { .name = "vgen2", }, 467f2518480SRobin Gong { .name = "vgen3", }, 468f2518480SRobin Gong { .name = "vgen4", }, 469f2518480SRobin Gong { .name = "vgen5", }, 470f2518480SRobin Gong { .name = "vgen6", }, 471c6182ac9SGeorge McCollister { .name = "coin", }, 472f2518480SRobin Gong }; 473f2518480SRobin Gong 474e5a7a72cSRobin Gong /* PFUZE3000 */ 475e5a7a72cSRobin Gong static struct of_regulator_match pfuze3000_matches[] = { 476e5a7a72cSRobin Gong 477e5a7a72cSRobin Gong { .name = "sw1a", }, 478e5a7a72cSRobin Gong { .name = "sw1b", }, 479e5a7a72cSRobin Gong { .name = "sw2", }, 480e5a7a72cSRobin Gong { .name = "sw3", }, 481e5a7a72cSRobin Gong { .name = "swbst", }, 482e5a7a72cSRobin Gong { .name = "vsnvs", }, 483e5a7a72cSRobin Gong { .name = "vrefddr", }, 484e5a7a72cSRobin Gong { .name = "vldo1", }, 485e5a7a72cSRobin Gong { .name = "vldo2", }, 486e5a7a72cSRobin Gong { .name = "vccsd", }, 487e5a7a72cSRobin Gong { .name = "v33", }, 488e5a7a72cSRobin Gong { .name = "vldo3", }, 489e5a7a72cSRobin Gong { .name = "vldo4", }, 490e5a7a72cSRobin Gong }; 491e5a7a72cSRobin Gong 492297101abSStefan Wahren /* PFUZE3001 */ 493297101abSStefan Wahren static struct of_regulator_match pfuze3001_matches[] = { 494297101abSStefan Wahren 495297101abSStefan Wahren { .name = "sw1", }, 496297101abSStefan Wahren { .name = "sw2", }, 497297101abSStefan Wahren { .name = "sw3", }, 498297101abSStefan Wahren { .name = "vsnvs", }, 499297101abSStefan Wahren { .name = "vldo1", }, 500297101abSStefan Wahren { .name = "vldo2", }, 501297101abSStefan Wahren { .name = "vccsd", }, 502297101abSStefan Wahren { .name = "v33", }, 503297101abSStefan Wahren { .name = "vldo3", }, 504297101abSStefan Wahren { .name = "vldo4", }, 505297101abSStefan Wahren }; 506297101abSStefan Wahren 507f2518480SRobin Gong static struct of_regulator_match *pfuze_matches; 508f2518480SRobin Gong 5093784b6d6SRobin Gong static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) 5103784b6d6SRobin Gong { 5113784b6d6SRobin Gong struct device *dev = chip->dev; 5123784b6d6SRobin Gong struct device_node *np, *parent; 5133784b6d6SRobin Gong int ret; 5143784b6d6SRobin Gong 5153e01c75aSFabio Estevam np = of_node_get(dev->of_node); 5163784b6d6SRobin Gong if (!np) 5176428789eSFabio Estevam return -EINVAL; 5183784b6d6SRobin Gong 5199d2fd4f0SMarco Felsch if (of_property_read_bool(np, "fsl,pfuze-support-disable-sw")) 5209d2fd4f0SMarco Felsch chip->flags |= PFUZE_FLAG_DISABLE_SW; 5219d2fd4f0SMarco Felsch 522d7857c42SSachin Kamat parent = of_get_child_by_name(np, "regulators"); 5233784b6d6SRobin Gong if (!parent) { 5243784b6d6SRobin Gong dev_err(dev, "regulators node not found\n"); 525afaa7b93SMiaoqian Lin of_node_put(np); 5263784b6d6SRobin Gong return -EINVAL; 5273784b6d6SRobin Gong } 5283784b6d6SRobin Gong 529f2518480SRobin Gong switch (chip->chip_id) { 530297101abSStefan Wahren case PFUZE3001: 531297101abSStefan Wahren pfuze_matches = pfuze3001_matches; 532297101abSStefan Wahren ret = of_regulator_match(dev, parent, pfuze3001_matches, 533297101abSStefan Wahren ARRAY_SIZE(pfuze3001_matches)); 534297101abSStefan Wahren break; 535e5a7a72cSRobin Gong case PFUZE3000: 536e5a7a72cSRobin Gong pfuze_matches = pfuze3000_matches; 537e5a7a72cSRobin Gong ret = of_regulator_match(dev, parent, pfuze3000_matches, 538e5a7a72cSRobin Gong ARRAY_SIZE(pfuze3000_matches)); 539e5a7a72cSRobin Gong break; 540f2518480SRobin Gong case PFUZE200: 541f2518480SRobin Gong pfuze_matches = pfuze200_matches; 542f2518480SRobin Gong ret = of_regulator_match(dev, parent, pfuze200_matches, 543f2518480SRobin Gong ARRAY_SIZE(pfuze200_matches)); 544f2518480SRobin Gong break; 545f2518480SRobin Gong 546f2518480SRobin Gong case PFUZE100: 547f2518480SRobin Gong default: 548f2518480SRobin Gong pfuze_matches = pfuze100_matches; 5493784b6d6SRobin Gong ret = of_regulator_match(dev, parent, pfuze100_matches, 5503784b6d6SRobin Gong ARRAY_SIZE(pfuze100_matches)); 551f2518480SRobin Gong break; 552f2518480SRobin Gong } 5533784b6d6SRobin Gong 5543784b6d6SRobin Gong of_node_put(parent); 555afaa7b93SMiaoqian Lin of_node_put(np); 5563784b6d6SRobin Gong if (ret < 0) { 5573784b6d6SRobin Gong dev_err(dev, "Error parsing regulator init data: %d\n", 5583784b6d6SRobin Gong ret); 5593784b6d6SRobin Gong return ret; 5603784b6d6SRobin Gong } 5613784b6d6SRobin Gong 5623784b6d6SRobin Gong return 0; 5633784b6d6SRobin Gong } 5643784b6d6SRobin Gong 5653784b6d6SRobin Gong static inline struct regulator_init_data *match_init_data(int index) 5663784b6d6SRobin Gong { 567f2518480SRobin Gong return pfuze_matches[index].init_data; 5683784b6d6SRobin Gong } 5693784b6d6SRobin Gong 5703784b6d6SRobin Gong static inline struct device_node *match_of_node(int index) 5713784b6d6SRobin Gong { 572f2518480SRobin Gong return pfuze_matches[index].of_node; 5733784b6d6SRobin Gong } 5743784b6d6SRobin Gong 57502a1124dSDmitry Osipenko static int pfuze_power_off_prepare(struct sys_off_data *data) 576c29daffaSOleksij Rempel { 57702a1124dSDmitry Osipenko struct pfuze_chip *syspm_pfuze_chip = data->cb_data; 57802a1124dSDmitry Osipenko 579db6565afSColin Ian King dev_info(syspm_pfuze_chip->dev, "Configure standby mode for power off"); 580c29daffaSOleksij Rempel 581c29daffaSOleksij Rempel /* Switch from default mode: APS/APS to APS/Off */ 582c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1ABMODE, 583c29daffaSOleksij Rempel PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); 584c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1CMODE, 585c29daffaSOleksij Rempel PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); 586c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW2MODE, 587c29daffaSOleksij Rempel PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); 588c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3AMODE, 589c29daffaSOleksij Rempel PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); 590c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3BMODE, 591c29daffaSOleksij Rempel PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); 592c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW4MODE, 593c29daffaSOleksij Rempel PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); 594c29daffaSOleksij Rempel 595c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN1VOL, 596c29daffaSOleksij Rempel PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, 597c29daffaSOleksij Rempel PFUZE100_VGENxSTBY); 598c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN2VOL, 599c29daffaSOleksij Rempel PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, 600c29daffaSOleksij Rempel PFUZE100_VGENxSTBY); 601c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN3VOL, 602c29daffaSOleksij Rempel PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, 603c29daffaSOleksij Rempel PFUZE100_VGENxSTBY); 604c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN4VOL, 605c29daffaSOleksij Rempel PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, 606c29daffaSOleksij Rempel PFUZE100_VGENxSTBY); 607c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN5VOL, 608c29daffaSOleksij Rempel PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, 609c29daffaSOleksij Rempel PFUZE100_VGENxSTBY); 610c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN6VOL, 611c29daffaSOleksij Rempel PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, 612c29daffaSOleksij Rempel PFUZE100_VGENxSTBY); 61302a1124dSDmitry Osipenko 61402a1124dSDmitry Osipenko return NOTIFY_DONE; 615c29daffaSOleksij Rempel } 616c29daffaSOleksij Rempel 617c29daffaSOleksij Rempel static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip) 618c29daffaSOleksij Rempel { 61902a1124dSDmitry Osipenko int err; 62002a1124dSDmitry Osipenko 621c29daffaSOleksij Rempel if (pfuze_chip->chip_id != PFUZE100) { 622c29daffaSOleksij Rempel dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare handler for not supported chip\n"); 623c29daffaSOleksij Rempel return -ENODEV; 624c29daffaSOleksij Rempel } 625c29daffaSOleksij Rempel 62602a1124dSDmitry Osipenko err = devm_register_sys_off_handler(pfuze_chip->dev, 62702a1124dSDmitry Osipenko SYS_OFF_MODE_POWER_OFF_PREPARE, 62802a1124dSDmitry Osipenko SYS_OFF_PRIO_DEFAULT, 62902a1124dSDmitry Osipenko pfuze_power_off_prepare, 63002a1124dSDmitry Osipenko pfuze_chip); 63102a1124dSDmitry Osipenko if (err) { 63202a1124dSDmitry Osipenko dev_err(pfuze_chip->dev, "failed to register sys-off handler: %d\n", 63302a1124dSDmitry Osipenko err); 63402a1124dSDmitry Osipenko return err; 635c29daffaSOleksij Rempel } 636c29daffaSOleksij Rempel 637c29daffaSOleksij Rempel return 0; 638c29daffaSOleksij Rempel } 639c29daffaSOleksij Rempel 6403784b6d6SRobin Gong static int pfuze_identify(struct pfuze_chip *pfuze_chip) 6413784b6d6SRobin Gong { 6423784b6d6SRobin Gong unsigned int value; 6433784b6d6SRobin Gong int ret; 6443784b6d6SRobin Gong 6453784b6d6SRobin Gong ret = regmap_read(pfuze_chip->regmap, PFUZE100_DEVICEID, &value); 6463784b6d6SRobin Gong if (ret) 6473784b6d6SRobin Gong return ret; 6483784b6d6SRobin Gong 649f2518480SRobin Gong if (((value & 0x0f) == 0x8) && (pfuze_chip->chip_id == PFUZE100)) { 65062b38916SFabio Estevam /* 65162b38916SFabio Estevam * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013 652f2518480SRobin Gong * as ID=8 in PFUZE100 65362b38916SFabio Estevam */ 654236c427cSTim Harvey dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8"); 655e5a7a72cSRobin Gong } else if ((value & 0x0f) != pfuze_chip->chip_id && 656297101abSStefan Wahren (value & 0xf0) >> 4 != pfuze_chip->chip_id && 657297101abSStefan Wahren (value != pfuze_chip->chip_id)) { 658f2518480SRobin Gong /* device id NOT match with your setting */ 6593784b6d6SRobin Gong dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value); 6603784b6d6SRobin Gong return -ENODEV; 6613784b6d6SRobin Gong } 6623784b6d6SRobin Gong 6633784b6d6SRobin Gong ret = regmap_read(pfuze_chip->regmap, PFUZE100_REVID, &value); 6643784b6d6SRobin Gong if (ret) 6653784b6d6SRobin Gong return ret; 6663784b6d6SRobin Gong dev_info(pfuze_chip->dev, 667f2694383SFabio Estevam "Full layer: %x, Metal layer: %x\n", 6683784b6d6SRobin Gong (value & 0xf0) >> 4, value & 0x0f); 6693784b6d6SRobin Gong 6703784b6d6SRobin Gong ret = regmap_read(pfuze_chip->regmap, PFUZE100_FABID, &value); 6713784b6d6SRobin Gong if (ret) 6723784b6d6SRobin Gong return ret; 6733784b6d6SRobin Gong dev_info(pfuze_chip->dev, "FAB: %x, FIN: %x\n", 6743784b6d6SRobin Gong (value & 0xc) >> 2, value & 0x3); 6753784b6d6SRobin Gong 6763784b6d6SRobin Gong return 0; 6773784b6d6SRobin Gong } 6783784b6d6SRobin Gong 6793784b6d6SRobin Gong static const struct regmap_config pfuze_regmap_config = { 6803784b6d6SRobin Gong .reg_bits = 8, 6813784b6d6SRobin Gong .val_bits = 8, 6826b8430c3SAxel Lin .max_register = PFUZE_NUMREGS - 1, 683*0332f074SBo Liu .cache_type = REGCACHE_MAPLE, 6843784b6d6SRobin Gong }; 6853784b6d6SRobin Gong 6868348c710SUwe Kleine-König static int pfuze100_regulator_probe(struct i2c_client *client) 6873784b6d6SRobin Gong { 6888348c710SUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(client); 6893784b6d6SRobin Gong struct pfuze_chip *pfuze_chip; 6903784b6d6SRobin Gong struct regulator_config config = { }; 6913784b6d6SRobin Gong int i, ret; 692f2518480SRobin Gong const struct of_device_id *match; 693f2518480SRobin Gong u32 regulator_num; 694e5a7a72cSRobin Gong u32 sw_check_start, sw_check_end, sw_hi = 0x40; 6953784b6d6SRobin Gong 6963784b6d6SRobin Gong pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip), 6973784b6d6SRobin Gong GFP_KERNEL); 6983784b6d6SRobin Gong if (!pfuze_chip) 6993784b6d6SRobin Gong return -ENOMEM; 7003784b6d6SRobin Gong 701f2518480SRobin Gong if (client->dev.of_node) { 7029e8925ebSChen Jiahao match = of_match_device(pfuze_dt_ids, &client->dev); 703f2518480SRobin Gong if (!match) { 704f2518480SRobin Gong dev_err(&client->dev, "Error: No device match found\n"); 705f2518480SRobin Gong return -ENODEV; 706f2518480SRobin Gong } 707f2518480SRobin Gong pfuze_chip->chip_id = (int)(long)match->data; 708f2518480SRobin Gong } else if (id) { 709f2518480SRobin Gong pfuze_chip->chip_id = id->driver_data; 710f2518480SRobin Gong } else { 711f2518480SRobin Gong dev_err(&client->dev, "No dts match or id table match found\n"); 712f2518480SRobin Gong return -ENODEV; 713f2518480SRobin Gong } 714f2518480SRobin Gong 7158c86ab25SAxel Lin i2c_set_clientdata(client, pfuze_chip); 7163784b6d6SRobin Gong pfuze_chip->dev = &client->dev; 7173784b6d6SRobin Gong 7183784b6d6SRobin Gong pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config); 7193784b6d6SRobin Gong if (IS_ERR(pfuze_chip->regmap)) { 7203784b6d6SRobin Gong ret = PTR_ERR(pfuze_chip->regmap); 7213784b6d6SRobin Gong dev_err(&client->dev, 7223784b6d6SRobin Gong "regmap allocation failed with err %d\n", ret); 7233784b6d6SRobin Gong return ret; 7243784b6d6SRobin Gong } 7253784b6d6SRobin Gong 7263784b6d6SRobin Gong ret = pfuze_identify(pfuze_chip); 7273784b6d6SRobin Gong if (ret) { 7283784b6d6SRobin Gong dev_err(&client->dev, "unrecognized pfuze chip ID!\n"); 7293784b6d6SRobin Gong return ret; 7303784b6d6SRobin Gong } 7313784b6d6SRobin Gong 732f2518480SRobin Gong /* use the right regulators after identify the right device */ 733f2518480SRobin Gong switch (pfuze_chip->chip_id) { 734297101abSStefan Wahren case PFUZE3001: 735297101abSStefan Wahren pfuze_chip->pfuze_regulators = pfuze3001_regulators; 736297101abSStefan Wahren regulator_num = ARRAY_SIZE(pfuze3001_regulators); 737297101abSStefan Wahren sw_check_start = PFUZE3001_SW2; 738297101abSStefan Wahren sw_check_end = PFUZE3001_SW2; 739297101abSStefan Wahren sw_hi = 1 << 3; 740297101abSStefan Wahren break; 741e5a7a72cSRobin Gong case PFUZE3000: 74212425654SFabio Estevam pfuze_chip->pfuze_regulators = pfuze3000_regulators; 743e5a7a72cSRobin Gong regulator_num = ARRAY_SIZE(pfuze3000_regulators); 744e5a7a72cSRobin Gong sw_check_start = PFUZE3000_SW2; 745e5a7a72cSRobin Gong sw_check_end = PFUZE3000_SW2; 746e5a7a72cSRobin Gong sw_hi = 1 << 3; 747e5a7a72cSRobin Gong break; 748f2518480SRobin Gong case PFUZE200: 74912425654SFabio Estevam pfuze_chip->pfuze_regulators = pfuze200_regulators; 750f2518480SRobin Gong regulator_num = ARRAY_SIZE(pfuze200_regulators); 751f2518480SRobin Gong sw_check_start = PFUZE200_SW2; 752f2518480SRobin Gong sw_check_end = PFUZE200_SW3B; 753f2518480SRobin Gong break; 754f2518480SRobin Gong case PFUZE100: 755f2518480SRobin Gong default: 75612425654SFabio Estevam pfuze_chip->pfuze_regulators = pfuze100_regulators; 757f2518480SRobin Gong regulator_num = ARRAY_SIZE(pfuze100_regulators); 758f2518480SRobin Gong sw_check_start = PFUZE100_SW2; 759f2518480SRobin Gong sw_check_end = PFUZE100_SW4; 760f2518480SRobin Gong break; 761f2518480SRobin Gong } 762f2518480SRobin Gong dev_info(&client->dev, "pfuze%s found.\n", 763e5a7a72cSRobin Gong (pfuze_chip->chip_id == PFUZE100) ? "100" : 764297101abSStefan Wahren (((pfuze_chip->chip_id == PFUZE200) ? "200" : 765297101abSStefan Wahren ((pfuze_chip->chip_id == PFUZE3000) ? "3000" : "3001")))); 766f2518480SRobin Gong 76712425654SFabio Estevam memcpy(pfuze_chip->regulator_descs, pfuze_chip->pfuze_regulators, 76878e1e867SXiaolei Wang regulator_num * sizeof(struct pfuze_regulator)); 769f2518480SRobin Gong 7703784b6d6SRobin Gong ret = pfuze_parse_regulators_dt(pfuze_chip); 7713784b6d6SRobin Gong if (ret) 7723784b6d6SRobin Gong return ret; 7733784b6d6SRobin Gong 774f2518480SRobin Gong for (i = 0; i < regulator_num; i++) { 7753784b6d6SRobin Gong struct regulator_init_data *init_data; 776d9493234SAxel Lin struct regulator_desc *desc; 7773784b6d6SRobin Gong int val; 7783784b6d6SRobin Gong 779d9493234SAxel Lin desc = &pfuze_chip->regulator_descs[i].desc; 780d9493234SAxel Lin 7813784b6d6SRobin Gong init_data = match_init_data(i); 7823784b6d6SRobin Gong 7833784b6d6SRobin Gong /* SW2~SW4 high bit check and modify the voltage value table */ 784f2518480SRobin Gong if (i >= sw_check_start && i <= sw_check_end) { 7851252b283SYizhuo ret = regmap_read(pfuze_chip->regmap, 7861252b283SYizhuo desc->vsel_reg, &val); 7871252b283SYizhuo if (ret) { 7881252b283SYizhuo dev_err(&client->dev, "Fails to read from the register.\n"); 7891252b283SYizhuo return ret; 7901252b283SYizhuo } 7911252b283SYizhuo 792e5a7a72cSRobin Gong if (val & sw_hi) { 793297101abSStefan Wahren if (pfuze_chip->chip_id == PFUZE3000 || 794297101abSStefan Wahren pfuze_chip->chip_id == PFUZE3001) { 795e5a7a72cSRobin Gong desc->volt_table = pfuze3000_sw2hi; 796e5a7a72cSRobin Gong desc->n_voltages = ARRAY_SIZE(pfuze3000_sw2hi); 797e5a7a72cSRobin Gong } else { 798d9493234SAxel Lin desc->min_uV = 800000; 799d9493234SAxel Lin desc->uV_step = 50000; 800d9493234SAxel Lin desc->n_voltages = 51; 8013784b6d6SRobin Gong } 8023784b6d6SRobin Gong } 803e5a7a72cSRobin Gong } 8043784b6d6SRobin Gong 8059d2fd4f0SMarco Felsch /* 8069d2fd4f0SMarco Felsch * Allow SW regulators to turn off. Checking it trough a flag is 8079d2fd4f0SMarco Felsch * a workaround to keep the backward compatibility with existing 8089d2fd4f0SMarco Felsch * old dtb's which may relay on the fact that we didn't disable 8099d2fd4f0SMarco Felsch * the switched regulator till yet. 8109d2fd4f0SMarco Felsch */ 8119d2fd4f0SMarco Felsch if (pfuze_chip->flags & PFUZE_FLAG_DISABLE_SW) { 812365ec8b6SSean Nyekjaer if (pfuze_chip->chip_id == PFUZE100 || 813365ec8b6SSean Nyekjaer pfuze_chip->chip_id == PFUZE200) { 8149d2fd4f0SMarco Felsch if (pfuze_chip->regulator_descs[i].sw_reg) { 8159d2fd4f0SMarco Felsch desc->ops = &pfuze100_sw_disable_regulator_ops; 8169d2fd4f0SMarco Felsch desc->enable_val = 0x8; 8179d2fd4f0SMarco Felsch desc->disable_val = 0x0; 8189d2fd4f0SMarco Felsch desc->enable_time = 500; 8199d2fd4f0SMarco Felsch } 8209d2fd4f0SMarco Felsch } 821365ec8b6SSean Nyekjaer } 8229d2fd4f0SMarco Felsch 8233784b6d6SRobin Gong config.dev = &client->dev; 8243784b6d6SRobin Gong config.init_data = init_data; 8253784b6d6SRobin Gong config.driver_data = pfuze_chip; 8263784b6d6SRobin Gong config.of_node = match_of_node(i); 8273784b6d6SRobin Gong 828f5247b40SJingoo Han pfuze_chip->regulators[i] = 829f5247b40SJingoo Han devm_regulator_register(&client->dev, desc, &config); 8303784b6d6SRobin Gong if (IS_ERR(pfuze_chip->regulators[i])) { 8313784b6d6SRobin Gong dev_err(&client->dev, "register regulator%s failed\n", 83212425654SFabio Estevam pfuze_chip->pfuze_regulators[i].desc.name); 833f5247b40SJingoo Han return PTR_ERR(pfuze_chip->regulators[i]); 8343784b6d6SRobin Gong } 8353784b6d6SRobin Gong } 8363784b6d6SRobin Gong 837c29daffaSOleksij Rempel if (of_property_read_bool(client->dev.of_node, 838c29daffaSOleksij Rempel "fsl,pmic-stby-poweroff")) 839c29daffaSOleksij Rempel return pfuze_power_off_prepare_init(pfuze_chip); 840c29daffaSOleksij Rempel 841c29daffaSOleksij Rempel return 0; 842c29daffaSOleksij Rempel } 843c29daffaSOleksij Rempel 8443784b6d6SRobin Gong static struct i2c_driver pfuze_driver = { 8453784b6d6SRobin Gong .driver = { 8463784b6d6SRobin Gong .name = "pfuze100-regulator", 847259b93b2SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS, 8483784b6d6SRobin Gong .of_match_table = pfuze_dt_ids, 8493784b6d6SRobin Gong }, 850964e1865SUwe Kleine-König .probe = pfuze100_regulator_probe, 8513784b6d6SRobin Gong }; 8523784b6d6SRobin Gong module_i2c_driver(pfuze_driver); 8533784b6d6SRobin Gong 8543784b6d6SRobin Gong MODULE_AUTHOR("Robin Gong <b38343@freescale.com>"); 855297101abSStefan Wahren MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/200/3000/3001 PMIC"); 85612d20fc2SRobin Gong MODULE_LICENSE("GPL v2"); 857