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> 133784b6d6SRobin Gong #include <linux/regulator/driver.h> 143784b6d6SRobin Gong #include <linux/regulator/machine.h> 153784b6d6SRobin Gong #include <linux/regulator/pfuze100.h> 163784b6d6SRobin Gong #include <linux/i2c.h> 173784b6d6SRobin Gong #include <linux/slab.h> 183784b6d6SRobin Gong #include <linux/regmap.h> 193784b6d6SRobin Gong 209d2fd4f0SMarco Felsch #define PFUZE_FLAG_DISABLE_SW BIT(1) 219d2fd4f0SMarco Felsch 223784b6d6SRobin Gong #define PFUZE_NUMREGS 128 233784b6d6SRobin Gong #define PFUZE100_VOL_OFFSET 0 243784b6d6SRobin Gong #define PFUZE100_STANDBY_OFFSET 1 253784b6d6SRobin Gong #define PFUZE100_MODE_OFFSET 3 263784b6d6SRobin Gong #define PFUZE100_CONF_OFFSET 4 273784b6d6SRobin Gong 283784b6d6SRobin Gong #define PFUZE100_DEVICEID 0x0 293784b6d6SRobin Gong #define PFUZE100_REVID 0x3 30a1b6fa85SAxel Lin #define PFUZE100_FABID 0x4 313784b6d6SRobin Gong 32c6182ac9SGeorge McCollister #define PFUZE100_COINVOL 0x1a 333784b6d6SRobin Gong #define PFUZE100_SW1ABVOL 0x20 34c29daffaSOleksij Rempel #define PFUZE100_SW1ABMODE 0x23 353784b6d6SRobin Gong #define PFUZE100_SW1CVOL 0x2e 36c29daffaSOleksij Rempel #define PFUZE100_SW1CMODE 0x31 373784b6d6SRobin Gong #define PFUZE100_SW2VOL 0x35 38c29daffaSOleksij Rempel #define PFUZE100_SW2MODE 0x38 393784b6d6SRobin Gong #define PFUZE100_SW3AVOL 0x3c 40c29daffaSOleksij Rempel #define PFUZE100_SW3AMODE 0x3f 413784b6d6SRobin Gong #define PFUZE100_SW3BVOL 0x43 42c29daffaSOleksij Rempel #define PFUZE100_SW3BMODE 0x46 433784b6d6SRobin Gong #define PFUZE100_SW4VOL 0x4a 44c29daffaSOleksij Rempel #define PFUZE100_SW4MODE 0x4d 453784b6d6SRobin Gong #define PFUZE100_SWBSTCON1 0x66 463784b6d6SRobin Gong #define PFUZE100_VREFDDRCON 0x6a 473784b6d6SRobin Gong #define PFUZE100_VSNVSVOL 0x6b 483784b6d6SRobin Gong #define PFUZE100_VGEN1VOL 0x6c 493784b6d6SRobin Gong #define PFUZE100_VGEN2VOL 0x6d 503784b6d6SRobin Gong #define PFUZE100_VGEN3VOL 0x6e 513784b6d6SRobin Gong #define PFUZE100_VGEN4VOL 0x6f 523784b6d6SRobin Gong #define PFUZE100_VGEN5VOL 0x70 533784b6d6SRobin Gong #define PFUZE100_VGEN6VOL 0x71 543784b6d6SRobin Gong 55c29daffaSOleksij Rempel #define PFUZE100_SWxMODE_MASK 0xf 56c29daffaSOleksij Rempel #define PFUZE100_SWxMODE_APS_APS 0x8 57c29daffaSOleksij Rempel #define PFUZE100_SWxMODE_APS_OFF 0x4 58c29daffaSOleksij Rempel 59c29daffaSOleksij Rempel #define PFUZE100_VGENxLPWR BIT(6) 60c29daffaSOleksij Rempel #define PFUZE100_VGENxSTBY BIT(5) 61c29daffaSOleksij Rempel 62297101abSStefan Wahren enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3, PFUZE3001 = 0x31, }; 63f2518480SRobin Gong 643784b6d6SRobin Gong struct pfuze_regulator { 653784b6d6SRobin Gong struct regulator_desc desc; 663784b6d6SRobin Gong unsigned char stby_reg; 673784b6d6SRobin Gong unsigned char stby_mask; 689d2fd4f0SMarco Felsch bool sw_reg; 693784b6d6SRobin Gong }; 703784b6d6SRobin Gong 713784b6d6SRobin Gong struct pfuze_chip { 72f2518480SRobin Gong int chip_id; 739d2fd4f0SMarco Felsch int flags; 743784b6d6SRobin Gong struct regmap *regmap; 753784b6d6SRobin Gong struct device *dev; 763784b6d6SRobin Gong struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR]; 773784b6d6SRobin Gong struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR]; 7812425654SFabio Estevam struct pfuze_regulator *pfuze_regulators; 793784b6d6SRobin Gong }; 803784b6d6SRobin Gong 813784b6d6SRobin Gong static const int pfuze100_swbst[] = { 823784b6d6SRobin Gong 5000000, 5050000, 5100000, 5150000, 833784b6d6SRobin Gong }; 843784b6d6SRobin Gong 853784b6d6SRobin Gong static const int pfuze100_vsnvs[] = { 863784b6d6SRobin Gong 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000, 873784b6d6SRobin Gong }; 883784b6d6SRobin Gong 89c6182ac9SGeorge McCollister static const int pfuze100_coin[] = { 90c6182ac9SGeorge McCollister 2500000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000, 91c6182ac9SGeorge McCollister }; 92c6182ac9SGeorge McCollister 931dced996SAnson Huang static const int pfuze3000_sw1a[] = { 941dced996SAnson Huang 700000, 725000, 750000, 775000, 800000, 825000, 850000, 875000, 951dced996SAnson Huang 900000, 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 961dced996SAnson Huang 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 971dced996SAnson Huang 1300000, 1325000, 1350000, 1375000, 1400000, 1425000, 1800000, 3300000, 981dced996SAnson Huang }; 991dced996SAnson Huang 100e5a7a72cSRobin Gong static const int pfuze3000_sw2lo[] = { 101e5a7a72cSRobin Gong 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 102e5a7a72cSRobin Gong }; 103e5a7a72cSRobin Gong 104e5a7a72cSRobin Gong static const int pfuze3000_sw2hi[] = { 105e5a7a72cSRobin Gong 2500000, 2800000, 2850000, 3000000, 3100000, 3150000, 3200000, 3300000, 106e5a7a72cSRobin Gong }; 107e5a7a72cSRobin Gong 1083784b6d6SRobin Gong static const struct i2c_device_id pfuze_device_id[] = { 109f2518480SRobin Gong {.name = "pfuze100", .driver_data = PFUZE100}, 110f2518480SRobin Gong {.name = "pfuze200", .driver_data = PFUZE200}, 111e5a7a72cSRobin Gong {.name = "pfuze3000", .driver_data = PFUZE3000}, 112297101abSStefan Wahren {.name = "pfuze3001", .driver_data = PFUZE3001}, 113e6c4c337SAxel Lin { } 1143784b6d6SRobin Gong }; 1153784b6d6SRobin Gong MODULE_DEVICE_TABLE(i2c, pfuze_device_id); 1163784b6d6SRobin Gong 1173784b6d6SRobin Gong static const struct of_device_id pfuze_dt_ids[] = { 118f2518480SRobin Gong { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100}, 119f2518480SRobin Gong { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200}, 120e5a7a72cSRobin Gong { .compatible = "fsl,pfuze3000", .data = (void *)PFUZE3000}, 121297101abSStefan Wahren { .compatible = "fsl,pfuze3001", .data = (void *)PFUZE3001}, 122e6c4c337SAxel Lin { } 1233784b6d6SRobin Gong }; 1243784b6d6SRobin Gong MODULE_DEVICE_TABLE(of, pfuze_dt_ids); 1253784b6d6SRobin Gong 1263784b6d6SRobin Gong static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) 1273784b6d6SRobin Gong { 1283784b6d6SRobin Gong struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev); 129d55efa4dSThiago Farina int id = rdev_get_id(rdev); 130297101abSStefan Wahren bool reg_has_ramp_delay; 131*a7503a9dSRobin Gong unsigned int ramp_bits = 0; 1323784b6d6SRobin Gong int ret; 1333784b6d6SRobin Gong 134297101abSStefan Wahren switch (pfuze100->chip_id) { 135297101abSStefan Wahren case PFUZE3001: 136297101abSStefan Wahren /* no dynamic voltage scaling for PF3001 */ 137297101abSStefan Wahren reg_has_ramp_delay = false; 138297101abSStefan Wahren break; 139297101abSStefan Wahren case PFUZE3000: 140297101abSStefan Wahren reg_has_ramp_delay = (id < PFUZE3000_SWBST); 141297101abSStefan Wahren break; 142297101abSStefan Wahren case PFUZE200: 143297101abSStefan Wahren reg_has_ramp_delay = (id < PFUZE200_SWBST); 144297101abSStefan Wahren break; 145297101abSStefan Wahren case PFUZE100: 146297101abSStefan Wahren default: 147297101abSStefan Wahren reg_has_ramp_delay = (id < PFUZE100_SWBST); 148297101abSStefan Wahren break; 149297101abSStefan Wahren } 150297101abSStefan Wahren 151297101abSStefan Wahren if (reg_has_ramp_delay) { 152*a7503a9dSRobin Gong if (ramp_delay > 0) { 153e5656669SAxel Lin ramp_delay = 12500 / ramp_delay; 1543784b6d6SRobin Gong ramp_bits = (ramp_delay >> 1) - (ramp_delay >> 3); 155*a7503a9dSRobin Gong } 156*a7503a9dSRobin Gong 157e5656669SAxel Lin ret = regmap_update_bits(pfuze100->regmap, 158e5656669SAxel Lin rdev->desc->vsel_reg + 4, 159e5656669SAxel Lin 0xc0, ramp_bits << 6); 1603784b6d6SRobin Gong if (ret < 0) 1613784b6d6SRobin Gong dev_err(pfuze100->dev, "ramp failed, err %d\n", ret); 162297101abSStefan Wahren } else { 1633784b6d6SRobin Gong ret = -EACCES; 164297101abSStefan Wahren } 1653784b6d6SRobin Gong 1663784b6d6SRobin Gong return ret; 1673784b6d6SRobin Gong } 1683784b6d6SRobin Gong 169e5053853SBhumika Goyal static const struct regulator_ops pfuze100_ldo_regulator_ops = { 1703784b6d6SRobin Gong .enable = regulator_enable_regmap, 1713784b6d6SRobin Gong .disable = regulator_disable_regmap, 1723784b6d6SRobin Gong .is_enabled = regulator_is_enabled_regmap, 1733784b6d6SRobin Gong .list_voltage = regulator_list_voltage_linear, 1743784b6d6SRobin Gong .set_voltage_sel = regulator_set_voltage_sel_regmap, 1753784b6d6SRobin Gong .get_voltage_sel = regulator_get_voltage_sel_regmap, 1763784b6d6SRobin Gong }; 1773784b6d6SRobin Gong 178e5053853SBhumika Goyal static const struct regulator_ops pfuze100_fixed_regulator_ops = { 179ab3ca774SAxel Lin .enable = regulator_enable_regmap, 180ab3ca774SAxel Lin .disable = regulator_disable_regmap, 181ab3ca774SAxel Lin .is_enabled = regulator_is_enabled_regmap, 1823784b6d6SRobin Gong .list_voltage = regulator_list_voltage_linear, 1833784b6d6SRobin Gong }; 1843784b6d6SRobin Gong 185e5053853SBhumika Goyal static const struct regulator_ops pfuze100_sw_regulator_ops = { 1863784b6d6SRobin Gong .list_voltage = regulator_list_voltage_linear, 1873784b6d6SRobin Gong .set_voltage_sel = regulator_set_voltage_sel_regmap, 1883784b6d6SRobin Gong .get_voltage_sel = regulator_get_voltage_sel_regmap, 1893784b6d6SRobin Gong .set_voltage_time_sel = regulator_set_voltage_time_sel, 1903784b6d6SRobin Gong .set_ramp_delay = pfuze100_set_ramp_delay, 1913784b6d6SRobin Gong }; 1923784b6d6SRobin Gong 1939d2fd4f0SMarco Felsch static const struct regulator_ops pfuze100_sw_disable_regulator_ops = { 1949d2fd4f0SMarco Felsch .enable = regulator_enable_regmap, 1959d2fd4f0SMarco Felsch .disable = regulator_disable_regmap, 1969d2fd4f0SMarco Felsch .is_enabled = regulator_is_enabled_regmap, 1979d2fd4f0SMarco Felsch .list_voltage = regulator_list_voltage_linear, 1989d2fd4f0SMarco Felsch .set_voltage_sel = regulator_set_voltage_sel_regmap, 1999d2fd4f0SMarco Felsch .get_voltage_sel = regulator_get_voltage_sel_regmap, 2009d2fd4f0SMarco Felsch .set_voltage_time_sel = regulator_set_voltage_time_sel, 2019d2fd4f0SMarco Felsch .set_ramp_delay = pfuze100_set_ramp_delay, 2029d2fd4f0SMarco Felsch }; 2039d2fd4f0SMarco Felsch 204e5053853SBhumika Goyal static const struct regulator_ops pfuze100_swb_regulator_ops = { 205a6dcf978SSean Cross .enable = regulator_enable_regmap, 206a6dcf978SSean Cross .disable = regulator_disable_regmap, 2070b01fd3dSAnson Huang .is_enabled = regulator_is_enabled_regmap, 2083784b6d6SRobin Gong .list_voltage = regulator_list_voltage_table, 2092e04cc41SAxel Lin .map_voltage = regulator_map_voltage_ascend, 2103784b6d6SRobin Gong .set_voltage_sel = regulator_set_voltage_sel_regmap, 2113784b6d6SRobin Gong .get_voltage_sel = regulator_get_voltage_sel_regmap, 2123784b6d6SRobin Gong 2133784b6d6SRobin Gong }; 2143784b6d6SRobin Gong 2156f1cf525SRobin Gong static const struct regulator_ops pfuze3000_sw_regulator_ops = { 2166f1cf525SRobin Gong .enable = regulator_enable_regmap, 2176f1cf525SRobin Gong .disable = regulator_disable_regmap, 2186f1cf525SRobin Gong .is_enabled = regulator_is_enabled_regmap, 2196f1cf525SRobin Gong .list_voltage = regulator_list_voltage_table, 2206f1cf525SRobin Gong .map_voltage = regulator_map_voltage_ascend, 2216f1cf525SRobin Gong .set_voltage_sel = regulator_set_voltage_sel_regmap, 2226f1cf525SRobin Gong .get_voltage_sel = regulator_get_voltage_sel_regmap, 2236f1cf525SRobin Gong .set_voltage_time_sel = regulator_set_voltage_time_sel, 2246f1cf525SRobin Gong .set_ramp_delay = pfuze100_set_ramp_delay, 2256f1cf525SRobin Gong 2266f1cf525SRobin Gong }; 2276f1cf525SRobin Gong 228f2518480SRobin Gong #define PFUZE100_FIXED_REG(_chip, _name, base, voltage) \ 229f2518480SRobin Gong [_chip ## _ ## _name] = { \ 2303784b6d6SRobin Gong .desc = { \ 2313784b6d6SRobin Gong .name = #_name, \ 2323784b6d6SRobin Gong .n_voltages = 1, \ 2333784b6d6SRobin Gong .ops = &pfuze100_fixed_regulator_ops, \ 2343784b6d6SRobin Gong .type = REGULATOR_VOLTAGE, \ 235f2518480SRobin Gong .id = _chip ## _ ## _name, \ 2363784b6d6SRobin Gong .owner = THIS_MODULE, \ 2373784b6d6SRobin Gong .min_uV = (voltage), \ 2383784b6d6SRobin Gong .enable_reg = (base), \ 2393784b6d6SRobin Gong .enable_mask = 0x10, \ 2403784b6d6SRobin Gong }, \ 2413784b6d6SRobin Gong } 2423784b6d6SRobin Gong 243f2518480SRobin Gong #define PFUZE100_SW_REG(_chip, _name, base, min, max, step) \ 244f2518480SRobin Gong [_chip ## _ ## _name] = { \ 2453784b6d6SRobin Gong .desc = { \ 2463784b6d6SRobin Gong .name = #_name,\ 2473784b6d6SRobin Gong .n_voltages = ((max) - (min)) / (step) + 1, \ 2483784b6d6SRobin Gong .ops = &pfuze100_sw_regulator_ops, \ 2493784b6d6SRobin Gong .type = REGULATOR_VOLTAGE, \ 250f2518480SRobin Gong .id = _chip ## _ ## _name, \ 2513784b6d6SRobin Gong .owner = THIS_MODULE, \ 2523784b6d6SRobin Gong .min_uV = (min), \ 2533784b6d6SRobin Gong .uV_step = (step), \ 2543784b6d6SRobin Gong .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ 2553784b6d6SRobin Gong .vsel_mask = 0x3f, \ 2569d2fd4f0SMarco Felsch .enable_reg = (base) + PFUZE100_MODE_OFFSET, \ 2579d2fd4f0SMarco Felsch .enable_mask = 0xf, \ 2583784b6d6SRobin Gong }, \ 2593784b6d6SRobin Gong .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ 2603784b6d6SRobin Gong .stby_mask = 0x3f, \ 2619d2fd4f0SMarco Felsch .sw_reg = true, \ 2623784b6d6SRobin Gong } 2633784b6d6SRobin Gong 264f2518480SRobin Gong #define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages) \ 265f2518480SRobin Gong [_chip ## _ ## _name] = { \ 2663784b6d6SRobin Gong .desc = { \ 2673784b6d6SRobin Gong .name = #_name, \ 2683784b6d6SRobin Gong .n_voltages = ARRAY_SIZE(voltages), \ 2693784b6d6SRobin Gong .ops = &pfuze100_swb_regulator_ops, \ 2703784b6d6SRobin Gong .type = REGULATOR_VOLTAGE, \ 271f2518480SRobin Gong .id = _chip ## _ ## _name, \ 2723784b6d6SRobin Gong .owner = THIS_MODULE, \ 2733784b6d6SRobin Gong .volt_table = voltages, \ 2743784b6d6SRobin Gong .vsel_reg = (base), \ 2753784b6d6SRobin Gong .vsel_mask = (mask), \ 276a6dcf978SSean Cross .enable_reg = (base), \ 277a6dcf978SSean Cross .enable_mask = 0x48, \ 2783784b6d6SRobin Gong }, \ 2793784b6d6SRobin Gong } 2803784b6d6SRobin Gong 281f2518480SRobin Gong #define PFUZE100_VGEN_REG(_chip, _name, base, min, max, step) \ 282f2518480SRobin Gong [_chip ## _ ## _name] = { \ 2833784b6d6SRobin Gong .desc = { \ 2843784b6d6SRobin Gong .name = #_name, \ 2853784b6d6SRobin Gong .n_voltages = ((max) - (min)) / (step) + 1, \ 2863784b6d6SRobin Gong .ops = &pfuze100_ldo_regulator_ops, \ 2873784b6d6SRobin Gong .type = REGULATOR_VOLTAGE, \ 288f2518480SRobin Gong .id = _chip ## _ ## _name, \ 2893784b6d6SRobin Gong .owner = THIS_MODULE, \ 2903784b6d6SRobin Gong .min_uV = (min), \ 2913784b6d6SRobin Gong .uV_step = (step), \ 2923784b6d6SRobin Gong .vsel_reg = (base), \ 2933784b6d6SRobin Gong .vsel_mask = 0xf, \ 2943784b6d6SRobin Gong .enable_reg = (base), \ 2953784b6d6SRobin Gong .enable_mask = 0x10, \ 2963784b6d6SRobin Gong }, \ 2973784b6d6SRobin Gong .stby_reg = (base), \ 2983784b6d6SRobin Gong .stby_mask = 0x20, \ 2993784b6d6SRobin Gong } 3003784b6d6SRobin Gong 301c6182ac9SGeorge McCollister #define PFUZE100_COIN_REG(_chip, _name, base, mask, voltages) \ 302c6182ac9SGeorge McCollister [_chip ## _ ## _name] = { \ 303c6182ac9SGeorge McCollister .desc = { \ 304c6182ac9SGeorge McCollister .name = #_name, \ 305c6182ac9SGeorge McCollister .n_voltages = ARRAY_SIZE(voltages), \ 306c6182ac9SGeorge McCollister .ops = &pfuze100_swb_regulator_ops, \ 307c6182ac9SGeorge McCollister .type = REGULATOR_VOLTAGE, \ 308c6182ac9SGeorge McCollister .id = _chip ## _ ## _name, \ 309c6182ac9SGeorge McCollister .owner = THIS_MODULE, \ 310c6182ac9SGeorge McCollister .volt_table = voltages, \ 311c6182ac9SGeorge McCollister .vsel_reg = (base), \ 312c6182ac9SGeorge McCollister .vsel_mask = (mask), \ 313c6182ac9SGeorge McCollister .enable_reg = (base), \ 314c6182ac9SGeorge McCollister .enable_mask = 0x8, \ 315c6182ac9SGeorge McCollister }, \ 316c6182ac9SGeorge McCollister } 317c6182ac9SGeorge McCollister 318e5a7a72cSRobin Gong #define PFUZE3000_VCC_REG(_chip, _name, base, min, max, step) { \ 319e5a7a72cSRobin Gong .desc = { \ 320e5a7a72cSRobin Gong .name = #_name, \ 321e5a7a72cSRobin Gong .n_voltages = ((max) - (min)) / (step) + 1, \ 322e5a7a72cSRobin Gong .ops = &pfuze100_ldo_regulator_ops, \ 323e5a7a72cSRobin Gong .type = REGULATOR_VOLTAGE, \ 324e5a7a72cSRobin Gong .id = _chip ## _ ## _name, \ 325e5a7a72cSRobin Gong .owner = THIS_MODULE, \ 326e5a7a72cSRobin Gong .min_uV = (min), \ 327e5a7a72cSRobin Gong .uV_step = (step), \ 328e5a7a72cSRobin Gong .vsel_reg = (base), \ 329e5a7a72cSRobin Gong .vsel_mask = 0x3, \ 330e5a7a72cSRobin Gong .enable_reg = (base), \ 331e5a7a72cSRobin Gong .enable_mask = 0x10, \ 332e5a7a72cSRobin Gong }, \ 333e5a7a72cSRobin Gong .stby_reg = (base), \ 334e5a7a72cSRobin Gong .stby_mask = 0x20, \ 335e5a7a72cSRobin Gong } 336e5a7a72cSRobin Gong 3376f1cf525SRobin Gong /* No linar case for the some switches of PFUZE3000 */ 3386f1cf525SRobin Gong #define PFUZE3000_SW_REG(_chip, _name, base, mask, voltages) \ 3396f1cf525SRobin Gong [_chip ## _ ## _name] = { \ 340e5a7a72cSRobin Gong .desc = { \ 341e5a7a72cSRobin Gong .name = #_name, \ 3426f1cf525SRobin Gong .n_voltages = ARRAY_SIZE(voltages), \ 3436f1cf525SRobin Gong .ops = &pfuze3000_sw_regulator_ops, \ 344e5a7a72cSRobin Gong .type = REGULATOR_VOLTAGE, \ 345e5a7a72cSRobin Gong .id = _chip ## _ ## _name, \ 346e5a7a72cSRobin Gong .owner = THIS_MODULE, \ 3476f1cf525SRobin Gong .volt_table = voltages, \ 348e5a7a72cSRobin Gong .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ 3496f1cf525SRobin Gong .vsel_mask = (mask), \ 3506f1cf525SRobin Gong .enable_reg = (base) + PFUZE100_MODE_OFFSET, \ 3516f1cf525SRobin Gong .enable_mask = 0xf, \ 3526f1cf525SRobin Gong .enable_val = 0x8, \ 3536f1cf525SRobin Gong .enable_time = 500, \ 354e5a7a72cSRobin Gong }, \ 355e5a7a72cSRobin Gong .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ 3566f1cf525SRobin Gong .stby_mask = (mask), \ 3576f1cf525SRobin Gong .sw_reg = true, \ 358e5a7a72cSRobin Gong } 359e5a7a72cSRobin Gong 360e5a7a72cSRobin Gong #define PFUZE3000_SW3_REG(_chip, _name, base, min, max, step) { \ 361e5a7a72cSRobin Gong .desc = { \ 362e5a7a72cSRobin Gong .name = #_name,\ 363e5a7a72cSRobin Gong .n_voltages = ((max) - (min)) / (step) + 1, \ 364e5a7a72cSRobin Gong .ops = &pfuze100_sw_regulator_ops, \ 365e5a7a72cSRobin Gong .type = REGULATOR_VOLTAGE, \ 366e5a7a72cSRobin Gong .id = _chip ## _ ## _name, \ 367e5a7a72cSRobin Gong .owner = THIS_MODULE, \ 368e5a7a72cSRobin Gong .min_uV = (min), \ 369e5a7a72cSRobin Gong .uV_step = (step), \ 370e5a7a72cSRobin Gong .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ 371e5a7a72cSRobin Gong .vsel_mask = 0xf, \ 372e5a7a72cSRobin Gong }, \ 373e5a7a72cSRobin Gong .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ 374e5a7a72cSRobin Gong .stby_mask = 0xf, \ 375e5a7a72cSRobin Gong } 376e5a7a72cSRobin Gong 377f2518480SRobin Gong /* PFUZE100 */ 3783784b6d6SRobin Gong static struct pfuze_regulator pfuze100_regulators[] = { 379f2518480SRobin Gong PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), 380f2518480SRobin Gong PFUZE100_SW_REG(PFUZE100, SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000), 381f2518480SRobin Gong PFUZE100_SW_REG(PFUZE100, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), 382f2518480SRobin Gong PFUZE100_SW_REG(PFUZE100, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), 383f2518480SRobin Gong PFUZE100_SW_REG(PFUZE100, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), 384f2518480SRobin Gong PFUZE100_SW_REG(PFUZE100, SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000), 385f2518480SRobin Gong PFUZE100_SWB_REG(PFUZE100, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), 386f2518480SRobin Gong PFUZE100_SWB_REG(PFUZE100, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), 387f2518480SRobin Gong PFUZE100_FIXED_REG(PFUZE100, VREFDDR, PFUZE100_VREFDDRCON, 750000), 388f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE100, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), 389f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE100, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), 390f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE100, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), 391f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), 392f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), 393f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), 39461d0de05SAdam Ford PFUZE100_COIN_REG(PFUZE100, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin), 3953784b6d6SRobin Gong }; 3963784b6d6SRobin Gong 397f2518480SRobin Gong static struct pfuze_regulator pfuze200_regulators[] = { 398f2518480SRobin Gong PFUZE100_SW_REG(PFUZE200, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), 399f2518480SRobin Gong PFUZE100_SW_REG(PFUZE200, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), 400f2518480SRobin Gong PFUZE100_SW_REG(PFUZE200, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), 401f2518480SRobin Gong PFUZE100_SW_REG(PFUZE200, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), 402f2518480SRobin Gong PFUZE100_SWB_REG(PFUZE200, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), 403f2518480SRobin Gong PFUZE100_SWB_REG(PFUZE200, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), 404f2518480SRobin Gong PFUZE100_FIXED_REG(PFUZE200, VREFDDR, PFUZE100_VREFDDRCON, 750000), 405f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE200, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), 406f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE200, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), 407f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE200, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), 408f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE200, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), 409f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE200, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), 410f2518480SRobin Gong PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), 411c6182ac9SGeorge McCollister PFUZE100_COIN_REG(PFUZE200, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin), 412f2518480SRobin Gong }; 413f2518480SRobin Gong 414e5a7a72cSRobin Gong static struct pfuze_regulator pfuze3000_regulators[] = { 4156f1cf525SRobin Gong PFUZE3000_SW_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a), 416e5a7a72cSRobin Gong PFUZE100_SW_REG(PFUZE3000, SW1B, PFUZE100_SW1CVOL, 700000, 1475000, 25000), 4176f1cf525SRobin Gong PFUZE3000_SW_REG(PFUZE3000, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo), 418e5a7a72cSRobin Gong PFUZE3000_SW3_REG(PFUZE3000, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000), 419e5a7a72cSRobin Gong PFUZE100_SWB_REG(PFUZE3000, SWBST, PFUZE100_SWBSTCON1, 0x3, pfuze100_swbst), 420e5a7a72cSRobin Gong PFUZE100_SWB_REG(PFUZE3000, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), 421e5a7a72cSRobin Gong PFUZE100_FIXED_REG(PFUZE3000, VREFDDR, PFUZE100_VREFDDRCON, 750000), 422e5a7a72cSRobin Gong PFUZE100_VGEN_REG(PFUZE3000, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000), 423e5a7a72cSRobin Gong PFUZE100_VGEN_REG(PFUZE3000, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), 424e5a7a72cSRobin Gong PFUZE3000_VCC_REG(PFUZE3000, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000), 425e5a7a72cSRobin Gong PFUZE3000_VCC_REG(PFUZE3000, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000), 426e5a7a72cSRobin Gong PFUZE100_VGEN_REG(PFUZE3000, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), 427e5a7a72cSRobin Gong PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), 428e5a7a72cSRobin Gong }; 429e5a7a72cSRobin Gong 430297101abSStefan Wahren static struct pfuze_regulator pfuze3001_regulators[] = { 4316f1cf525SRobin Gong PFUZE3000_SW_REG(PFUZE3001, SW1, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a), 4326f1cf525SRobin Gong PFUZE3000_SW_REG(PFUZE3001, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo), 433297101abSStefan Wahren PFUZE3000_SW3_REG(PFUZE3001, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000), 434297101abSStefan Wahren PFUZE100_SWB_REG(PFUZE3001, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), 435297101abSStefan Wahren PFUZE100_VGEN_REG(PFUZE3001, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000), 436297101abSStefan Wahren PFUZE100_VGEN_REG(PFUZE3001, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), 437297101abSStefan Wahren PFUZE3000_VCC_REG(PFUZE3001, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000), 438297101abSStefan Wahren PFUZE3000_VCC_REG(PFUZE3001, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000), 439297101abSStefan Wahren PFUZE100_VGEN_REG(PFUZE3001, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), 440297101abSStefan Wahren PFUZE100_VGEN_REG(PFUZE3001, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), 441297101abSStefan Wahren }; 442297101abSStefan Wahren 4433784b6d6SRobin Gong #ifdef CONFIG_OF 444f2518480SRobin Gong /* PFUZE100 */ 4453784b6d6SRobin Gong static struct of_regulator_match pfuze100_matches[] = { 4463784b6d6SRobin Gong { .name = "sw1ab", }, 4473784b6d6SRobin Gong { .name = "sw1c", }, 4483784b6d6SRobin Gong { .name = "sw2", }, 4493784b6d6SRobin Gong { .name = "sw3a", }, 4503784b6d6SRobin Gong { .name = "sw3b", }, 4513784b6d6SRobin Gong { .name = "sw4", }, 4523784b6d6SRobin Gong { .name = "swbst", }, 4533784b6d6SRobin Gong { .name = "vsnvs", }, 4543784b6d6SRobin Gong { .name = "vrefddr", }, 4553784b6d6SRobin Gong { .name = "vgen1", }, 4563784b6d6SRobin Gong { .name = "vgen2", }, 4573784b6d6SRobin Gong { .name = "vgen3", }, 4583784b6d6SRobin Gong { .name = "vgen4", }, 4593784b6d6SRobin Gong { .name = "vgen5", }, 4603784b6d6SRobin Gong { .name = "vgen6", }, 46161d0de05SAdam Ford { .name = "coin", }, 4623784b6d6SRobin Gong }; 4633784b6d6SRobin Gong 464f2518480SRobin Gong /* PFUZE200 */ 465f2518480SRobin Gong static struct of_regulator_match pfuze200_matches[] = { 466f2518480SRobin Gong 467f2518480SRobin Gong { .name = "sw1ab", }, 468f2518480SRobin Gong { .name = "sw2", }, 469f2518480SRobin Gong { .name = "sw3a", }, 470f2518480SRobin Gong { .name = "sw3b", }, 471f2518480SRobin Gong { .name = "swbst", }, 472f2518480SRobin Gong { .name = "vsnvs", }, 473f2518480SRobin Gong { .name = "vrefddr", }, 474f2518480SRobin Gong { .name = "vgen1", }, 475f2518480SRobin Gong { .name = "vgen2", }, 476f2518480SRobin Gong { .name = "vgen3", }, 477f2518480SRobin Gong { .name = "vgen4", }, 478f2518480SRobin Gong { .name = "vgen5", }, 479f2518480SRobin Gong { .name = "vgen6", }, 480c6182ac9SGeorge McCollister { .name = "coin", }, 481f2518480SRobin Gong }; 482f2518480SRobin Gong 483e5a7a72cSRobin Gong /* PFUZE3000 */ 484e5a7a72cSRobin Gong static struct of_regulator_match pfuze3000_matches[] = { 485e5a7a72cSRobin Gong 486e5a7a72cSRobin Gong { .name = "sw1a", }, 487e5a7a72cSRobin Gong { .name = "sw1b", }, 488e5a7a72cSRobin Gong { .name = "sw2", }, 489e5a7a72cSRobin Gong { .name = "sw3", }, 490e5a7a72cSRobin Gong { .name = "swbst", }, 491e5a7a72cSRobin Gong { .name = "vsnvs", }, 492e5a7a72cSRobin Gong { .name = "vrefddr", }, 493e5a7a72cSRobin Gong { .name = "vldo1", }, 494e5a7a72cSRobin Gong { .name = "vldo2", }, 495e5a7a72cSRobin Gong { .name = "vccsd", }, 496e5a7a72cSRobin Gong { .name = "v33", }, 497e5a7a72cSRobin Gong { .name = "vldo3", }, 498e5a7a72cSRobin Gong { .name = "vldo4", }, 499e5a7a72cSRobin Gong }; 500e5a7a72cSRobin Gong 501297101abSStefan Wahren /* PFUZE3001 */ 502297101abSStefan Wahren static struct of_regulator_match pfuze3001_matches[] = { 503297101abSStefan Wahren 504297101abSStefan Wahren { .name = "sw1", }, 505297101abSStefan Wahren { .name = "sw2", }, 506297101abSStefan Wahren { .name = "sw3", }, 507297101abSStefan Wahren { .name = "vsnvs", }, 508297101abSStefan Wahren { .name = "vldo1", }, 509297101abSStefan Wahren { .name = "vldo2", }, 510297101abSStefan Wahren { .name = "vccsd", }, 511297101abSStefan Wahren { .name = "v33", }, 512297101abSStefan Wahren { .name = "vldo3", }, 513297101abSStefan Wahren { .name = "vldo4", }, 514297101abSStefan Wahren }; 515297101abSStefan Wahren 516f2518480SRobin Gong static struct of_regulator_match *pfuze_matches; 517f2518480SRobin Gong 5183784b6d6SRobin Gong static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) 5193784b6d6SRobin Gong { 5203784b6d6SRobin Gong struct device *dev = chip->dev; 5213784b6d6SRobin Gong struct device_node *np, *parent; 5223784b6d6SRobin Gong int ret; 5233784b6d6SRobin Gong 5243e01c75aSFabio Estevam np = of_node_get(dev->of_node); 5253784b6d6SRobin Gong if (!np) 5266428789eSFabio Estevam return -EINVAL; 5273784b6d6SRobin Gong 5289d2fd4f0SMarco Felsch if (of_property_read_bool(np, "fsl,pfuze-support-disable-sw")) 5299d2fd4f0SMarco Felsch chip->flags |= PFUZE_FLAG_DISABLE_SW; 5309d2fd4f0SMarco Felsch 531d7857c42SSachin Kamat parent = of_get_child_by_name(np, "regulators"); 5323784b6d6SRobin Gong if (!parent) { 5333784b6d6SRobin Gong dev_err(dev, "regulators node not found\n"); 5343784b6d6SRobin Gong return -EINVAL; 5353784b6d6SRobin Gong } 5363784b6d6SRobin Gong 537f2518480SRobin Gong switch (chip->chip_id) { 538297101abSStefan Wahren case PFUZE3001: 539297101abSStefan Wahren pfuze_matches = pfuze3001_matches; 540297101abSStefan Wahren ret = of_regulator_match(dev, parent, pfuze3001_matches, 541297101abSStefan Wahren ARRAY_SIZE(pfuze3001_matches)); 542297101abSStefan Wahren break; 543e5a7a72cSRobin Gong case PFUZE3000: 544e5a7a72cSRobin Gong pfuze_matches = pfuze3000_matches; 545e5a7a72cSRobin Gong ret = of_regulator_match(dev, parent, pfuze3000_matches, 546e5a7a72cSRobin Gong ARRAY_SIZE(pfuze3000_matches)); 547e5a7a72cSRobin Gong break; 548f2518480SRobin Gong case PFUZE200: 549f2518480SRobin Gong pfuze_matches = pfuze200_matches; 550f2518480SRobin Gong ret = of_regulator_match(dev, parent, pfuze200_matches, 551f2518480SRobin Gong ARRAY_SIZE(pfuze200_matches)); 552f2518480SRobin Gong break; 553f2518480SRobin Gong 554f2518480SRobin Gong case PFUZE100: 555f2518480SRobin Gong default: 556f2518480SRobin Gong pfuze_matches = pfuze100_matches; 5573784b6d6SRobin Gong ret = of_regulator_match(dev, parent, pfuze100_matches, 5583784b6d6SRobin Gong ARRAY_SIZE(pfuze100_matches)); 559f2518480SRobin Gong break; 560f2518480SRobin Gong } 5613784b6d6SRobin Gong 5623784b6d6SRobin Gong of_node_put(parent); 5633784b6d6SRobin Gong if (ret < 0) { 5643784b6d6SRobin Gong dev_err(dev, "Error parsing regulator init data: %d\n", 5653784b6d6SRobin Gong ret); 5663784b6d6SRobin Gong return ret; 5673784b6d6SRobin Gong } 5683784b6d6SRobin Gong 5693784b6d6SRobin Gong return 0; 5703784b6d6SRobin Gong } 5713784b6d6SRobin Gong 5723784b6d6SRobin Gong static inline struct regulator_init_data *match_init_data(int index) 5733784b6d6SRobin Gong { 574f2518480SRobin Gong return pfuze_matches[index].init_data; 5753784b6d6SRobin Gong } 5763784b6d6SRobin Gong 5773784b6d6SRobin Gong static inline struct device_node *match_of_node(int index) 5783784b6d6SRobin Gong { 579f2518480SRobin Gong return pfuze_matches[index].of_node; 5803784b6d6SRobin Gong } 5813784b6d6SRobin Gong #else 5823784b6d6SRobin Gong static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) 5833784b6d6SRobin Gong { 584205c97bcSRobin Gong return 0; 5853784b6d6SRobin Gong } 5863784b6d6SRobin Gong 5873784b6d6SRobin Gong static inline struct regulator_init_data *match_init_data(int index) 5883784b6d6SRobin Gong { 5893784b6d6SRobin Gong return NULL; 5903784b6d6SRobin Gong } 5913784b6d6SRobin Gong 5923784b6d6SRobin Gong static inline struct device_node *match_of_node(int index) 5933784b6d6SRobin Gong { 5943784b6d6SRobin Gong return NULL; 5953784b6d6SRobin Gong } 5963784b6d6SRobin Gong #endif 5973784b6d6SRobin Gong 598c29daffaSOleksij Rempel static struct pfuze_chip *syspm_pfuze_chip; 599c29daffaSOleksij Rempel 600c29daffaSOleksij Rempel static void pfuze_power_off_prepare(void) 601c29daffaSOleksij Rempel { 602db6565afSColin Ian King dev_info(syspm_pfuze_chip->dev, "Configure standby mode for power off"); 603c29daffaSOleksij Rempel 604c29daffaSOleksij Rempel /* Switch from default mode: APS/APS to APS/Off */ 605c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1ABMODE, 606c29daffaSOleksij Rempel PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); 607c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1CMODE, 608c29daffaSOleksij Rempel PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); 609c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW2MODE, 610c29daffaSOleksij Rempel PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); 611c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3AMODE, 612c29daffaSOleksij Rempel PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); 613c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3BMODE, 614c29daffaSOleksij Rempel PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); 615c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW4MODE, 616c29daffaSOleksij Rempel PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF); 617c29daffaSOleksij Rempel 618c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN1VOL, 619c29daffaSOleksij Rempel PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, 620c29daffaSOleksij Rempel PFUZE100_VGENxSTBY); 621c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN2VOL, 622c29daffaSOleksij Rempel PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, 623c29daffaSOleksij Rempel PFUZE100_VGENxSTBY); 624c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN3VOL, 625c29daffaSOleksij Rempel PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, 626c29daffaSOleksij Rempel PFUZE100_VGENxSTBY); 627c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN4VOL, 628c29daffaSOleksij Rempel PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, 629c29daffaSOleksij Rempel PFUZE100_VGENxSTBY); 630c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN5VOL, 631c29daffaSOleksij Rempel PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, 632c29daffaSOleksij Rempel PFUZE100_VGENxSTBY); 633c29daffaSOleksij Rempel regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN6VOL, 634c29daffaSOleksij Rempel PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY, 635c29daffaSOleksij Rempel PFUZE100_VGENxSTBY); 636c29daffaSOleksij Rempel } 637c29daffaSOleksij Rempel 638c29daffaSOleksij Rempel static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip) 639c29daffaSOleksij Rempel { 640c29daffaSOleksij Rempel if (pfuze_chip->chip_id != PFUZE100) { 641c29daffaSOleksij Rempel dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare handler for not supported chip\n"); 642c29daffaSOleksij Rempel return -ENODEV; 643c29daffaSOleksij Rempel } 644c29daffaSOleksij Rempel 645c29daffaSOleksij Rempel if (pm_power_off_prepare) { 646c29daffaSOleksij Rempel dev_warn(pfuze_chip->dev, "pm_power_off_prepare is already registered.\n"); 647c29daffaSOleksij Rempel return -EBUSY; 648c29daffaSOleksij Rempel } 649c29daffaSOleksij Rempel 650c29daffaSOleksij Rempel if (syspm_pfuze_chip) { 651c29daffaSOleksij Rempel dev_warn(pfuze_chip->dev, "syspm_pfuze_chip is already set.\n"); 652c29daffaSOleksij Rempel return -EBUSY; 653c29daffaSOleksij Rempel } 654c29daffaSOleksij Rempel 655c29daffaSOleksij Rempel syspm_pfuze_chip = pfuze_chip; 656c29daffaSOleksij Rempel pm_power_off_prepare = pfuze_power_off_prepare; 657c29daffaSOleksij Rempel 658c29daffaSOleksij Rempel return 0; 659c29daffaSOleksij Rempel } 660c29daffaSOleksij Rempel 6613784b6d6SRobin Gong static int pfuze_identify(struct pfuze_chip *pfuze_chip) 6623784b6d6SRobin Gong { 6633784b6d6SRobin Gong unsigned int value; 6643784b6d6SRobin Gong int ret; 6653784b6d6SRobin Gong 6663784b6d6SRobin Gong ret = regmap_read(pfuze_chip->regmap, PFUZE100_DEVICEID, &value); 6673784b6d6SRobin Gong if (ret) 6683784b6d6SRobin Gong return ret; 6693784b6d6SRobin Gong 670f2518480SRobin Gong if (((value & 0x0f) == 0x8) && (pfuze_chip->chip_id == PFUZE100)) { 67162b38916SFabio Estevam /* 67262b38916SFabio Estevam * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013 673f2518480SRobin Gong * as ID=8 in PFUZE100 67462b38916SFabio Estevam */ 675236c427cSTim Harvey dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8"); 676e5a7a72cSRobin Gong } else if ((value & 0x0f) != pfuze_chip->chip_id && 677297101abSStefan Wahren (value & 0xf0) >> 4 != pfuze_chip->chip_id && 678297101abSStefan Wahren (value != pfuze_chip->chip_id)) { 679f2518480SRobin Gong /* device id NOT match with your setting */ 6803784b6d6SRobin Gong dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value); 6813784b6d6SRobin Gong return -ENODEV; 6823784b6d6SRobin Gong } 6833784b6d6SRobin Gong 6843784b6d6SRobin Gong ret = regmap_read(pfuze_chip->regmap, PFUZE100_REVID, &value); 6853784b6d6SRobin Gong if (ret) 6863784b6d6SRobin Gong return ret; 6873784b6d6SRobin Gong dev_info(pfuze_chip->dev, 688f2694383SFabio Estevam "Full layer: %x, Metal layer: %x\n", 6893784b6d6SRobin Gong (value & 0xf0) >> 4, value & 0x0f); 6903784b6d6SRobin Gong 6913784b6d6SRobin Gong ret = regmap_read(pfuze_chip->regmap, PFUZE100_FABID, &value); 6923784b6d6SRobin Gong if (ret) 6933784b6d6SRobin Gong return ret; 6943784b6d6SRobin Gong dev_info(pfuze_chip->dev, "FAB: %x, FIN: %x\n", 6953784b6d6SRobin Gong (value & 0xc) >> 2, value & 0x3); 6963784b6d6SRobin Gong 6973784b6d6SRobin Gong return 0; 6983784b6d6SRobin Gong } 6993784b6d6SRobin Gong 7003784b6d6SRobin Gong static const struct regmap_config pfuze_regmap_config = { 7013784b6d6SRobin Gong .reg_bits = 8, 7023784b6d6SRobin Gong .val_bits = 8, 7036b8430c3SAxel Lin .max_register = PFUZE_NUMREGS - 1, 7043784b6d6SRobin Gong .cache_type = REGCACHE_RBTREE, 7053784b6d6SRobin Gong }; 7063784b6d6SRobin Gong 7073784b6d6SRobin Gong static int pfuze100_regulator_probe(struct i2c_client *client, 7083784b6d6SRobin Gong const struct i2c_device_id *id) 7093784b6d6SRobin Gong { 7103784b6d6SRobin Gong struct pfuze_chip *pfuze_chip; 7113784b6d6SRobin Gong struct pfuze_regulator_platform_data *pdata = 7123784b6d6SRobin Gong dev_get_platdata(&client->dev); 7133784b6d6SRobin Gong struct regulator_config config = { }; 7143784b6d6SRobin Gong int i, ret; 715f2518480SRobin Gong const struct of_device_id *match; 716f2518480SRobin Gong u32 regulator_num; 717e5a7a72cSRobin Gong u32 sw_check_start, sw_check_end, sw_hi = 0x40; 7183784b6d6SRobin Gong 7193784b6d6SRobin Gong pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip), 7203784b6d6SRobin Gong GFP_KERNEL); 7213784b6d6SRobin Gong if (!pfuze_chip) 7223784b6d6SRobin Gong return -ENOMEM; 7233784b6d6SRobin Gong 724f2518480SRobin Gong if (client->dev.of_node) { 725f2518480SRobin Gong match = of_match_device(of_match_ptr(pfuze_dt_ids), 726f2518480SRobin Gong &client->dev); 727f2518480SRobin Gong if (!match) { 728f2518480SRobin Gong dev_err(&client->dev, "Error: No device match found\n"); 729f2518480SRobin Gong return -ENODEV; 730f2518480SRobin Gong } 731f2518480SRobin Gong pfuze_chip->chip_id = (int)(long)match->data; 732f2518480SRobin Gong } else if (id) { 733f2518480SRobin Gong pfuze_chip->chip_id = id->driver_data; 734f2518480SRobin Gong } else { 735f2518480SRobin Gong dev_err(&client->dev, "No dts match or id table match found\n"); 736f2518480SRobin Gong return -ENODEV; 737f2518480SRobin Gong } 738f2518480SRobin Gong 7398c86ab25SAxel Lin i2c_set_clientdata(client, pfuze_chip); 7403784b6d6SRobin Gong pfuze_chip->dev = &client->dev; 7413784b6d6SRobin Gong 7423784b6d6SRobin Gong pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config); 7433784b6d6SRobin Gong if (IS_ERR(pfuze_chip->regmap)) { 7443784b6d6SRobin Gong ret = PTR_ERR(pfuze_chip->regmap); 7453784b6d6SRobin Gong dev_err(&client->dev, 7463784b6d6SRobin Gong "regmap allocation failed with err %d\n", ret); 7473784b6d6SRobin Gong return ret; 7483784b6d6SRobin Gong } 7493784b6d6SRobin Gong 7503784b6d6SRobin Gong ret = pfuze_identify(pfuze_chip); 7513784b6d6SRobin Gong if (ret) { 7523784b6d6SRobin Gong dev_err(&client->dev, "unrecognized pfuze chip ID!\n"); 7533784b6d6SRobin Gong return ret; 7543784b6d6SRobin Gong } 7553784b6d6SRobin Gong 756f2518480SRobin Gong /* use the right regulators after identify the right device */ 757f2518480SRobin Gong switch (pfuze_chip->chip_id) { 758297101abSStefan Wahren case PFUZE3001: 759297101abSStefan Wahren pfuze_chip->pfuze_regulators = pfuze3001_regulators; 760297101abSStefan Wahren regulator_num = ARRAY_SIZE(pfuze3001_regulators); 761297101abSStefan Wahren sw_check_start = PFUZE3001_SW2; 762297101abSStefan Wahren sw_check_end = PFUZE3001_SW2; 763297101abSStefan Wahren sw_hi = 1 << 3; 764297101abSStefan Wahren break; 765e5a7a72cSRobin Gong case PFUZE3000: 76612425654SFabio Estevam pfuze_chip->pfuze_regulators = pfuze3000_regulators; 767e5a7a72cSRobin Gong regulator_num = ARRAY_SIZE(pfuze3000_regulators); 768e5a7a72cSRobin Gong sw_check_start = PFUZE3000_SW2; 769e5a7a72cSRobin Gong sw_check_end = PFUZE3000_SW2; 770e5a7a72cSRobin Gong sw_hi = 1 << 3; 771e5a7a72cSRobin Gong break; 772f2518480SRobin Gong case PFUZE200: 77312425654SFabio Estevam pfuze_chip->pfuze_regulators = pfuze200_regulators; 774f2518480SRobin Gong regulator_num = ARRAY_SIZE(pfuze200_regulators); 775f2518480SRobin Gong sw_check_start = PFUZE200_SW2; 776f2518480SRobin Gong sw_check_end = PFUZE200_SW3B; 777f2518480SRobin Gong break; 778f2518480SRobin Gong case PFUZE100: 779f2518480SRobin Gong default: 78012425654SFabio Estevam pfuze_chip->pfuze_regulators = pfuze100_regulators; 781f2518480SRobin Gong regulator_num = ARRAY_SIZE(pfuze100_regulators); 782f2518480SRobin Gong sw_check_start = PFUZE100_SW2; 783f2518480SRobin Gong sw_check_end = PFUZE100_SW4; 784f2518480SRobin Gong break; 785f2518480SRobin Gong } 786f2518480SRobin Gong dev_info(&client->dev, "pfuze%s found.\n", 787e5a7a72cSRobin Gong (pfuze_chip->chip_id == PFUZE100) ? "100" : 788297101abSStefan Wahren (((pfuze_chip->chip_id == PFUZE200) ? "200" : 789297101abSStefan Wahren ((pfuze_chip->chip_id == PFUZE3000) ? "3000" : "3001")))); 790f2518480SRobin Gong 79112425654SFabio Estevam memcpy(pfuze_chip->regulator_descs, pfuze_chip->pfuze_regulators, 792f2518480SRobin Gong sizeof(pfuze_chip->regulator_descs)); 793f2518480SRobin Gong 7943784b6d6SRobin Gong ret = pfuze_parse_regulators_dt(pfuze_chip); 7953784b6d6SRobin Gong if (ret) 7963784b6d6SRobin Gong return ret; 7973784b6d6SRobin Gong 798f2518480SRobin Gong for (i = 0; i < regulator_num; i++) { 7993784b6d6SRobin Gong struct regulator_init_data *init_data; 800d9493234SAxel Lin struct regulator_desc *desc; 8013784b6d6SRobin Gong int val; 8023784b6d6SRobin Gong 803d9493234SAxel Lin desc = &pfuze_chip->regulator_descs[i].desc; 804d9493234SAxel Lin 8053784b6d6SRobin Gong if (pdata) 8063784b6d6SRobin Gong init_data = pdata->init_data[i]; 8073784b6d6SRobin Gong else 8083784b6d6SRobin Gong init_data = match_init_data(i); 8093784b6d6SRobin Gong 8103784b6d6SRobin Gong /* SW2~SW4 high bit check and modify the voltage value table */ 811f2518480SRobin Gong if (i >= sw_check_start && i <= sw_check_end) { 8121252b283SYizhuo ret = regmap_read(pfuze_chip->regmap, 8131252b283SYizhuo desc->vsel_reg, &val); 8141252b283SYizhuo if (ret) { 8151252b283SYizhuo dev_err(&client->dev, "Fails to read from the register.\n"); 8161252b283SYizhuo return ret; 8171252b283SYizhuo } 8181252b283SYizhuo 819e5a7a72cSRobin Gong if (val & sw_hi) { 820297101abSStefan Wahren if (pfuze_chip->chip_id == PFUZE3000 || 821297101abSStefan Wahren pfuze_chip->chip_id == PFUZE3001) { 822e5a7a72cSRobin Gong desc->volt_table = pfuze3000_sw2hi; 823e5a7a72cSRobin Gong desc->n_voltages = ARRAY_SIZE(pfuze3000_sw2hi); 824e5a7a72cSRobin Gong } else { 825d9493234SAxel Lin desc->min_uV = 800000; 826d9493234SAxel Lin desc->uV_step = 50000; 827d9493234SAxel Lin desc->n_voltages = 51; 8283784b6d6SRobin Gong } 8293784b6d6SRobin Gong } 830e5a7a72cSRobin Gong } 8313784b6d6SRobin Gong 8329d2fd4f0SMarco Felsch /* 8339d2fd4f0SMarco Felsch * Allow SW regulators to turn off. Checking it trough a flag is 8349d2fd4f0SMarco Felsch * a workaround to keep the backward compatibility with existing 8359d2fd4f0SMarco Felsch * old dtb's which may relay on the fact that we didn't disable 8369d2fd4f0SMarco Felsch * the switched regulator till yet. 8379d2fd4f0SMarco Felsch */ 8389d2fd4f0SMarco Felsch if (pfuze_chip->flags & PFUZE_FLAG_DISABLE_SW) { 8399d2fd4f0SMarco Felsch if (pfuze_chip->regulator_descs[i].sw_reg) { 8409d2fd4f0SMarco Felsch desc->ops = &pfuze100_sw_disable_regulator_ops; 8419d2fd4f0SMarco Felsch desc->enable_val = 0x8; 8429d2fd4f0SMarco Felsch desc->disable_val = 0x0; 8439d2fd4f0SMarco Felsch desc->enable_time = 500; 8449d2fd4f0SMarco Felsch } 8459d2fd4f0SMarco Felsch } 8469d2fd4f0SMarco Felsch 8473784b6d6SRobin Gong config.dev = &client->dev; 8483784b6d6SRobin Gong config.init_data = init_data; 8493784b6d6SRobin Gong config.driver_data = pfuze_chip; 8503784b6d6SRobin Gong config.of_node = match_of_node(i); 8513784b6d6SRobin Gong 852f5247b40SJingoo Han pfuze_chip->regulators[i] = 853f5247b40SJingoo Han devm_regulator_register(&client->dev, desc, &config); 8543784b6d6SRobin Gong if (IS_ERR(pfuze_chip->regulators[i])) { 8553784b6d6SRobin Gong dev_err(&client->dev, "register regulator%s failed\n", 85612425654SFabio Estevam pfuze_chip->pfuze_regulators[i].desc.name); 857f5247b40SJingoo Han return PTR_ERR(pfuze_chip->regulators[i]); 8583784b6d6SRobin Gong } 8593784b6d6SRobin Gong } 8603784b6d6SRobin Gong 861c29daffaSOleksij Rempel if (of_property_read_bool(client->dev.of_node, 862c29daffaSOleksij Rempel "fsl,pmic-stby-poweroff")) 863c29daffaSOleksij Rempel return pfuze_power_off_prepare_init(pfuze_chip); 864c29daffaSOleksij Rempel 865c29daffaSOleksij Rempel return 0; 866c29daffaSOleksij Rempel } 867c29daffaSOleksij Rempel 868c29daffaSOleksij Rempel static int pfuze100_regulator_remove(struct i2c_client *client) 869c29daffaSOleksij Rempel { 870c29daffaSOleksij Rempel if (syspm_pfuze_chip) { 871c29daffaSOleksij Rempel syspm_pfuze_chip = NULL; 872c29daffaSOleksij Rempel pm_power_off_prepare = NULL; 873c29daffaSOleksij Rempel } 874c29daffaSOleksij Rempel 8753784b6d6SRobin Gong return 0; 8763784b6d6SRobin Gong } 8773784b6d6SRobin Gong 8783784b6d6SRobin Gong static struct i2c_driver pfuze_driver = { 8793784b6d6SRobin Gong .id_table = pfuze_device_id, 8803784b6d6SRobin Gong .driver = { 8813784b6d6SRobin Gong .name = "pfuze100-regulator", 8823784b6d6SRobin Gong .of_match_table = pfuze_dt_ids, 8833784b6d6SRobin Gong }, 8843784b6d6SRobin Gong .probe = pfuze100_regulator_probe, 885c29daffaSOleksij Rempel .remove = pfuze100_regulator_remove, 8863784b6d6SRobin Gong }; 8873784b6d6SRobin Gong module_i2c_driver(pfuze_driver); 8883784b6d6SRobin Gong 8893784b6d6SRobin Gong MODULE_AUTHOR("Robin Gong <b38343@freescale.com>"); 890297101abSStefan Wahren MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/200/3000/3001 PMIC"); 89112d20fc2SRobin Gong MODULE_LICENSE("GPL v2"); 892