1d3795d63SJagan Teki // SPDX-License-Identifier: GPL-2.0+ 2d3795d63SJagan Teki /* 3d3795d63SJagan Teki * Copyright (C) 2017 NXP 4d3795d63SJagan Teki * Copyright (C) 2019 Boundary Devices 5d3795d63SJagan Teki * Copyright (C) 2020 Amarula Solutions(India) 6d3795d63SJagan Teki */ 7d3795d63SJagan Teki 8d3795d63SJagan Teki #include <linux/delay.h> 9d3795d63SJagan Teki #include <linux/err.h> 10d3795d63SJagan Teki #include <linux/gpio/consumer.h> 11d3795d63SJagan Teki #include <linux/i2c.h> 12d3795d63SJagan Teki #include <linux/module.h> 13d3795d63SJagan Teki #include <linux/regmap.h> 14d3795d63SJagan Teki #include <linux/regulator/driver.h> 15d3795d63SJagan Teki #include <linux/regulator/machine.h> 16d3795d63SJagan Teki 17d3795d63SJagan Teki /* registers */ 18d3795d63SJagan Teki #define PF8X00_DEVICEID 0x00 19d3795d63SJagan Teki #define PF8X00_REVID 0x01 20d3795d63SJagan Teki #define PF8X00_EMREV 0x02 21d3795d63SJagan Teki #define PF8X00_PROGID 0x03 22d3795d63SJagan Teki #define PF8X00_IMS_INT 0x04 23d3795d63SJagan Teki #define PF8X00_IMS_THERM 0x07 24d3795d63SJagan Teki #define PF8X00_SW_MODE_INT 0x0a 25d3795d63SJagan Teki #define PF8X00_SW_MODE_MASK 0x0b 26d3795d63SJagan Teki #define PF8X00_IMS_SW_ILIM 0x12 27d3795d63SJagan Teki #define PF8X00_IMS_LDO_ILIM 0x15 28d3795d63SJagan Teki #define PF8X00_IMS_SW_UV 0x18 29d3795d63SJagan Teki #define PF8X00_IMS_SW_OV 0x1b 30d3795d63SJagan Teki #define PF8X00_IMS_LDO_UV 0x1e 31d3795d63SJagan Teki #define PF8X00_IMS_LDO_OV 0x21 32d3795d63SJagan Teki #define PF8X00_IMS_PWRON 0x24 33d3795d63SJagan Teki #define PF8X00_SYS_INT 0x27 34d3795d63SJagan Teki #define PF8X00_HARD_FAULT 0x29 35d3795d63SJagan Teki #define PF8X00_FSOB_FLAGS 0x2a 36d3795d63SJagan Teki #define PF8X00_FSOB_SELECT 0x2b 37d3795d63SJagan Teki #define PF8X00_ABIST_OV1 0x2c 38d3795d63SJagan Teki #define PF8X00_ABIST_OV2 0x2d 39d3795d63SJagan Teki #define PF8X00_ABIST_UV1 0x2e 40d3795d63SJagan Teki #define PF8X00_ABIST_UV2 0x2f 41d3795d63SJagan Teki #define PF8X00_TEST_FLAGS 0x30 42d3795d63SJagan Teki #define PF8X00_ABIST_RUN 0x31 43d3795d63SJagan Teki #define PF8X00_RANDOM_GEN 0x33 44d3795d63SJagan Teki #define PF8X00_RANDOM_CHK 0x34 45d3795d63SJagan Teki #define PF8X00_VMONEN1 0x35 46d3795d63SJagan Teki #define PF8X00_VMONEN2 0x36 47d3795d63SJagan Teki #define PF8X00_CTRL1 0x37 48d3795d63SJagan Teki #define PF8X00_CTRL2 0x38 49d3795d63SJagan Teki #define PF8X00_CTRL3 0x39 50d3795d63SJagan Teki #define PF8X00_PWRUP_CTRL 0x3a 51d3795d63SJagan Teki #define PF8X00_RESETBMCU 0x3c 52d3795d63SJagan Teki #define PF8X00_PGOOD 0x3d 53d3795d63SJagan Teki #define PF8X00_PWRDN_DLY1 0x3e 54d3795d63SJagan Teki #define PF8X00_PWRDN_DLY2 0x3f 55d3795d63SJagan Teki #define PF8X00_FREQ_CTRL 0x40 56d3795d63SJagan Teki #define PF8X00_COINCELL_CTRL 0x41 57d3795d63SJagan Teki #define PF8X00_PWRON 0x42 58d3795d63SJagan Teki #define PF8X00_WD_CONFIG 0x43 59d3795d63SJagan Teki #define PF8X00_WD_CLEAR 0x44 60d3795d63SJagan Teki #define PF8X00_WD_EXPIRE 0x45 61d3795d63SJagan Teki #define PF8X00_WD_COUNTER 0x46 62d3795d63SJagan Teki #define PF8X00_FAULT_COUNTER 0x47 63d3795d63SJagan Teki #define PF8X00_FSAFE_COUNTER 0x48 64d3795d63SJagan Teki #define PF8X00_FAULT_TIMER 0x49 65d3795d63SJagan Teki #define PF8X00_AMUX 0x4a 66d3795d63SJagan Teki #define PF8X00_SW1_CONFIG1 0x4d 67d3795d63SJagan Teki #define PF8X00_LDO1_CONFIG1 0x85 68d3795d63SJagan Teki #define PF8X00_VSNVS_CONFIG1 0x9d 69d3795d63SJagan Teki #define PF8X00_PAGE_SELECT 0x9f 70d3795d63SJagan Teki 71d3795d63SJagan Teki /* regulators */ 72d3795d63SJagan Teki enum pf8x00_regulators { 73d3795d63SJagan Teki PF8X00_LDO1, 74d3795d63SJagan Teki PF8X00_LDO2, 75d3795d63SJagan Teki PF8X00_LDO3, 76d3795d63SJagan Teki PF8X00_LDO4, 77d3795d63SJagan Teki PF8X00_BUCK1, 78d3795d63SJagan Teki PF8X00_BUCK2, 79d3795d63SJagan Teki PF8X00_BUCK3, 80d3795d63SJagan Teki PF8X00_BUCK4, 81d3795d63SJagan Teki PF8X00_BUCK5, 82d3795d63SJagan Teki PF8X00_BUCK6, 83d3795d63SJagan Teki PF8X00_BUCK7, 84d3795d63SJagan Teki PF8X00_VSNVS, 85d3795d63SJagan Teki 86d3795d63SJagan Teki PF8X00_MAX_REGULATORS, 87d3795d63SJagan Teki }; 88d3795d63SJagan Teki 89d3795d63SJagan Teki enum pf8x00_buck_states { 90d3795d63SJagan Teki SW_CONFIG1, 91d3795d63SJagan Teki SW_CONFIG2, 92d3795d63SJagan Teki SW_PWRUP, 93d3795d63SJagan Teki SW_MODE1, 94d3795d63SJagan Teki SW_RUN_VOLT, 95d3795d63SJagan Teki SW_STBY_VOLT, 96d3795d63SJagan Teki }; 97d3795d63SJagan Teki #define PF8X00_SW_BASE(i) (8 * (i - PF8X00_BUCK1) + PF8X00_SW1_CONFIG1) 98d3795d63SJagan Teki 99d3795d63SJagan Teki enum pf8x00_ldo_states { 100d3795d63SJagan Teki LDO_CONFIG1, 101d3795d63SJagan Teki LDO_CONFIG2, 102d3795d63SJagan Teki LDO_PWRUP, 103d3795d63SJagan Teki LDO_RUN_VOLT, 104d3795d63SJagan Teki LDO_STBY_VOLT, 105d3795d63SJagan Teki }; 106d3795d63SJagan Teki #define PF8X00_LDO_BASE(i) (6 * (i - PF8X00_LDO1) + PF8X00_LDO1_CONFIG1) 107d3795d63SJagan Teki 108d3795d63SJagan Teki enum swxilim_bits { 109d3795d63SJagan Teki SWXILIM_2100_MA, 110d3795d63SJagan Teki SWXILIM_2600_MA, 111d3795d63SJagan Teki SWXILIM_3000_MA, 112d3795d63SJagan Teki SWXILIM_4500_MA, 113d3795d63SJagan Teki }; 114d3795d63SJagan Teki #define PF8X00_SWXILIM_SHIFT 3 115d3795d63SJagan Teki #define PF8X00_SWXILIM_MASK GENMASK(4, 3) 116d3795d63SJagan Teki #define PF8X00_SWXPHASE_MASK GENMASK(2, 0) 117d3795d63SJagan Teki #define PF8X00_SWXPHASE_DEFAULT 0 118d3795d63SJagan Teki #define PF8X00_SWXPHASE_SHIFT 7 119d3795d63SJagan Teki 120d3795d63SJagan Teki enum pf8x00_devid { 121d3795d63SJagan Teki PF8100 = 0x0, 122d3795d63SJagan Teki PF8121A = BIT(1), 123d3795d63SJagan Teki PF8200 = BIT(3), 124d3795d63SJagan Teki }; 125d3795d63SJagan Teki #define PF8X00_FAM BIT(6) 126d3795d63SJagan Teki #define PF8X00_DEVICE_FAM_MASK GENMASK(7, 4) 127d3795d63SJagan Teki #define PF8X00_DEVICE_ID_MASK GENMASK(3, 0) 128d3795d63SJagan Teki 129d3795d63SJagan Teki struct pf8x00_regulator { 130d3795d63SJagan Teki struct regulator_desc desc; 131d3795d63SJagan Teki u8 phase_shift; 132d3795d63SJagan Teki }; 133d3795d63SJagan Teki 134d3795d63SJagan Teki struct pf8x00_chip { 135d3795d63SJagan Teki struct regmap *regmap; 136d3795d63SJagan Teki struct device *dev; 137d3795d63SJagan Teki }; 138d3795d63SJagan Teki 139d3795d63SJagan Teki static const struct regmap_config pf8x00_regmap_config = { 140d3795d63SJagan Teki .reg_bits = 8, 141d3795d63SJagan Teki .val_bits = 8, 142d3795d63SJagan Teki .max_register = PF8X00_PAGE_SELECT, 143d3795d63SJagan Teki .cache_type = REGCACHE_RBTREE, 144d3795d63SJagan Teki }; 145d3795d63SJagan Teki 146d3795d63SJagan Teki /* VLDOx output: 1.5V to 5.0V */ 147d3795d63SJagan Teki static const int pf8x00_ldo_voltages[] = { 148d3795d63SJagan Teki 1500000, 1600000, 1800000, 1850000, 2150000, 2500000, 2800000, 3000000, 149d3795d63SJagan Teki 3100000, 3150000, 3200000, 3300000, 3350000, 1650000, 1700000, 5000000, 150d3795d63SJagan Teki }; 151d3795d63SJagan Teki 152*245f5f65SAdrien Grassein /* Output: 2.1A to 4.5A */ 153*245f5f65SAdrien Grassein static const unsigned int pf8x00_sw_current_table[] = { 154*245f5f65SAdrien Grassein 2100000, 2600000, 3000000, 4500000, 155*245f5f65SAdrien Grassein }; 156*245f5f65SAdrien Grassein 157d3795d63SJagan Teki #define SWV(i) (6250 * i + 400000) 158d3795d63SJagan Teki #define SWV_LINE(i) SWV(i*8+0), SWV(i*8+1), SWV(i*8+2), SWV(i*8+3), \ 159d3795d63SJagan Teki SWV(i*8+4), SWV(i*8+5), SWV(i*8+6), SWV(i*8+7) 160d3795d63SJagan Teki 161d3795d63SJagan Teki /* Output: 0.4V to 1.8V */ 162d3795d63SJagan Teki static const int pf8x00_sw1_to_6_voltages[] = { 163d3795d63SJagan Teki SWV_LINE(0), 164d3795d63SJagan Teki SWV_LINE(1), 165d3795d63SJagan Teki SWV_LINE(2), 166d3795d63SJagan Teki SWV_LINE(3), 167d3795d63SJagan Teki SWV_LINE(4), 168d3795d63SJagan Teki SWV_LINE(5), 169d3795d63SJagan Teki SWV_LINE(6), 170d3795d63SJagan Teki SWV_LINE(7), 171d3795d63SJagan Teki SWV_LINE(8), 172d3795d63SJagan Teki SWV_LINE(9), 173d3795d63SJagan Teki SWV_LINE(10), 174d3795d63SJagan Teki SWV_LINE(11), 175d3795d63SJagan Teki SWV_LINE(12), 176d3795d63SJagan Teki SWV_LINE(13), 177d3795d63SJagan Teki SWV_LINE(14), 178d3795d63SJagan Teki SWV_LINE(15), 179d3795d63SJagan Teki SWV_LINE(16), 180d3795d63SJagan Teki SWV_LINE(17), 181d3795d63SJagan Teki SWV_LINE(18), 182d3795d63SJagan Teki SWV_LINE(19), 183d3795d63SJagan Teki SWV_LINE(20), 184d3795d63SJagan Teki SWV_LINE(21), 185d3795d63SJagan Teki 1500000, 1800000, 186d3795d63SJagan Teki }; 187d3795d63SJagan Teki 188d3795d63SJagan Teki /* Output: 1.0V to 4.1V */ 189d3795d63SJagan Teki static const int pf8x00_sw7_voltages[] = { 190d3795d63SJagan Teki 1000000, 1100000, 1200000, 1250000, 1300000, 1350000, 1500000, 1600000, 191d3795d63SJagan Teki 1800000, 1850000, 2000000, 2100000, 2150000, 2250000, 2300000, 2400000, 192d3795d63SJagan Teki 2500000, 2800000, 3150000, 3200000, 3250000, 3300000, 3350000, 3400000, 193d3795d63SJagan Teki 3500000, 3800000, 4000000, 4100000, 4100000, 4100000, 4100000, 4100000, 194d3795d63SJagan Teki }; 195d3795d63SJagan Teki 196d3795d63SJagan Teki /* Output: 1.8V, 3.0V, or 3.3V */ 197d3795d63SJagan Teki static const int pf8x00_vsnvs_voltages[] = { 198d3795d63SJagan Teki 0, 1800000, 3000000, 3300000, 199d3795d63SJagan Teki }; 200d3795d63SJagan Teki 201d3795d63SJagan Teki static struct pf8x00_regulator *desc_to_regulator(const struct regulator_desc *desc) 202d3795d63SJagan Teki { 203d3795d63SJagan Teki return container_of(desc, struct pf8x00_regulator, desc); 204d3795d63SJagan Teki } 205d3795d63SJagan Teki 206*245f5f65SAdrien Grassein static void swxilim_select(struct pf8x00_chip *chip, int id, int ilim) 207d3795d63SJagan Teki { 208d3795d63SJagan Teki u8 ilim_sel; 209*245f5f65SAdrien Grassein u8 reg = PF8X00_SW_BASE(id) + SW_CONFIG2; 210d3795d63SJagan Teki 211d3795d63SJagan Teki switch (ilim) { 212d3795d63SJagan Teki case 2100: 213d3795d63SJagan Teki ilim_sel = SWXILIM_2100_MA; 214d3795d63SJagan Teki break; 215d3795d63SJagan Teki case 2600: 216d3795d63SJagan Teki ilim_sel = SWXILIM_2600_MA; 217d3795d63SJagan Teki break; 218d3795d63SJagan Teki case 3000: 219d3795d63SJagan Teki ilim_sel = SWXILIM_3000_MA; 220d3795d63SJagan Teki break; 221d3795d63SJagan Teki case 4500: 222d3795d63SJagan Teki ilim_sel = SWXILIM_4500_MA; 223d3795d63SJagan Teki break; 224d3795d63SJagan Teki default: 225d3795d63SJagan Teki ilim_sel = SWXILIM_2100_MA; 226d3795d63SJagan Teki break; 227d3795d63SJagan Teki } 228d3795d63SJagan Teki 229*245f5f65SAdrien Grassein regmap_update_bits(chip->regmap, reg, 230*245f5f65SAdrien Grassein PF8X00_SWXILIM_MASK, 231*245f5f65SAdrien Grassein ilim_sel << PF8X00_SWXILIM_SHIFT); 232*245f5f65SAdrien Grassein } 233*245f5f65SAdrien Grassein 234*245f5f65SAdrien Grassein static void handle_ilim_property(struct device_node *np, 235*245f5f65SAdrien Grassein const struct regulator_desc *desc, 236*245f5f65SAdrien Grassein struct regulator_config *config) 237*245f5f65SAdrien Grassein { 238*245f5f65SAdrien Grassein struct pf8x00_chip *chip = config->driver_data; 239*245f5f65SAdrien Grassein int ret; 240*245f5f65SAdrien Grassein int val; 241*245f5f65SAdrien Grassein 242*245f5f65SAdrien Grassein if ((desc->id >= PF8X00_BUCK1) && (desc->id <= PF8X00_BUCK7)) { 243*245f5f65SAdrien Grassein ret = of_property_read_u32(np, "nxp,ilim-ma", &val); 244*245f5f65SAdrien Grassein if (ret) { 245*245f5f65SAdrien Grassein dev_dbg(chip->dev, "unspecified ilim for BUCK%d, use value stored in OTP\n", 246*245f5f65SAdrien Grassein desc->id - PF8X00_LDO4); 247*245f5f65SAdrien Grassein return; 248*245f5f65SAdrien Grassein } 249*245f5f65SAdrien Grassein 250*245f5f65SAdrien Grassein dev_warn(chip->dev, "nxp,ilim-ma is deprecated, please use regulator-max-microamp\n"); 251*245f5f65SAdrien Grassein swxilim_select(chip, desc->id, val); 252*245f5f65SAdrien Grassein 253*245f5f65SAdrien Grassein } else 254*245f5f65SAdrien Grassein dev_warn(chip->dev, "nxp,ilim-ma used with incorrect regulator (%d)\n", desc->id); 255d3795d63SJagan Teki } 256d3795d63SJagan Teki 257d3795d63SJagan Teki static int pf8x00_of_parse_cb(struct device_node *np, 258d3795d63SJagan Teki const struct regulator_desc *desc, 259d3795d63SJagan Teki struct regulator_config *config) 260d3795d63SJagan Teki { 261d3795d63SJagan Teki struct pf8x00_regulator *data = desc_to_regulator(desc); 262d3795d63SJagan Teki struct pf8x00_chip *chip = config->driver_data; 263d3795d63SJagan Teki int phase; 264d3795d63SJagan Teki int val; 265d3795d63SJagan Teki int ret; 266d3795d63SJagan Teki 267*245f5f65SAdrien Grassein handle_ilim_property(np, desc, config); 268d3795d63SJagan Teki 269d3795d63SJagan Teki ret = of_property_read_u32(np, "nxp,phase-shift", &val); 270d3795d63SJagan Teki if (ret) { 271d3795d63SJagan Teki dev_dbg(chip->dev, 272d3795d63SJagan Teki "unspecified phase-shift for BUCK%d, use 0 degrees\n", 273d3795d63SJagan Teki desc->id - PF8X00_LDO4); 274d3795d63SJagan Teki val = PF8X00_SWXPHASE_DEFAULT; 275d3795d63SJagan Teki } 276d3795d63SJagan Teki 277d3795d63SJagan Teki phase = val / 45; 278d3795d63SJagan Teki if ((phase * 45) != val) { 279d3795d63SJagan Teki dev_warn(config->dev, 280d3795d63SJagan Teki "invalid phase_shift %d for BUCK%d, use 0 degrees\n", 281d3795d63SJagan Teki (phase * 45), desc->id - PF8X00_LDO4); 282d3795d63SJagan Teki phase = PF8X00_SWXPHASE_SHIFT; 283d3795d63SJagan Teki } 284d3795d63SJagan Teki 285d3795d63SJagan Teki data->phase_shift = (phase >= 1) ? phase - 1 : PF8X00_SWXPHASE_SHIFT; 286d3795d63SJagan Teki 287d3795d63SJagan Teki return 0; 288d3795d63SJagan Teki } 289d3795d63SJagan Teki 290d3795d63SJagan Teki static const struct regulator_ops pf8x00_ldo_ops = { 291d3795d63SJagan Teki .enable = regulator_enable_regmap, 292d3795d63SJagan Teki .disable = regulator_disable_regmap, 293d3795d63SJagan Teki .is_enabled = regulator_is_enabled_regmap, 294d3795d63SJagan Teki .list_voltage = regulator_list_voltage_table, 295d3795d63SJagan Teki .set_voltage_sel = regulator_set_voltage_sel_regmap, 296d3795d63SJagan Teki .get_voltage_sel = regulator_get_voltage_sel_regmap, 297d3795d63SJagan Teki }; 298d3795d63SJagan Teki 299d3795d63SJagan Teki static const struct regulator_ops pf8x00_buck_ops = { 300d3795d63SJagan Teki .enable = regulator_enable_regmap, 301d3795d63SJagan Teki .disable = regulator_disable_regmap, 302d3795d63SJagan Teki .is_enabled = regulator_is_enabled_regmap, 303d3795d63SJagan Teki .list_voltage = regulator_list_voltage_table, 304d3795d63SJagan Teki .set_voltage_sel = regulator_set_voltage_sel_regmap, 305d3795d63SJagan Teki .get_voltage_sel = regulator_get_voltage_sel_regmap, 306*245f5f65SAdrien Grassein .get_current_limit = regulator_get_current_limit_regmap, 307*245f5f65SAdrien Grassein .set_current_limit = regulator_set_current_limit_regmap, 308d3795d63SJagan Teki }; 309d3795d63SJagan Teki 310d3795d63SJagan Teki static const struct regulator_ops pf8x00_vsnvs_ops = { 311d3795d63SJagan Teki .enable = regulator_enable_regmap, 312d3795d63SJagan Teki .disable = regulator_disable_regmap, 313d3795d63SJagan Teki .is_enabled = regulator_is_enabled_regmap, 314d3795d63SJagan Teki .list_voltage = regulator_list_voltage_table, 315d3795d63SJagan Teki .map_voltage = regulator_map_voltage_ascend, 316d3795d63SJagan Teki .set_voltage_sel = regulator_set_voltage_sel_regmap, 317d3795d63SJagan Teki .get_voltage_sel = regulator_get_voltage_sel_regmap, 318d3795d63SJagan Teki }; 319d3795d63SJagan Teki 320d3795d63SJagan Teki #define PF8X00LDO(_id, _name, base, voltages) \ 321d3795d63SJagan Teki [PF8X00_LDO ## _id] = { \ 322d3795d63SJagan Teki .desc = { \ 323d3795d63SJagan Teki .name = _name, \ 324d3795d63SJagan Teki .of_match = _name, \ 325d3795d63SJagan Teki .regulators_node = "regulators", \ 326d3795d63SJagan Teki .n_voltages = ARRAY_SIZE(voltages), \ 327d3795d63SJagan Teki .ops = &pf8x00_ldo_ops, \ 328d3795d63SJagan Teki .type = REGULATOR_VOLTAGE, \ 329d3795d63SJagan Teki .id = PF8X00_LDO ## _id, \ 330d3795d63SJagan Teki .owner = THIS_MODULE, \ 331d3795d63SJagan Teki .volt_table = voltages, \ 332d3795d63SJagan Teki .vsel_reg = (base) + LDO_RUN_VOLT, \ 333d3795d63SJagan Teki .vsel_mask = 0xff, \ 334d3795d63SJagan Teki .enable_reg = (base) + LDO_CONFIG2, \ 335d3795d63SJagan Teki .enable_val = 0x2, \ 336d3795d63SJagan Teki .disable_val = 0x0, \ 337d3795d63SJagan Teki .enable_mask = 2, \ 338d3795d63SJagan Teki }, \ 339d3795d63SJagan Teki } 340d3795d63SJagan Teki 341d3795d63SJagan Teki #define PF8X00BUCK(_id, _name, base, voltages) \ 342d3795d63SJagan Teki [PF8X00_BUCK ## _id] = { \ 343d3795d63SJagan Teki .desc = { \ 344d3795d63SJagan Teki .name = _name, \ 345d3795d63SJagan Teki .of_match = _name, \ 346d3795d63SJagan Teki .regulators_node = "regulators", \ 347d3795d63SJagan Teki .of_parse_cb = pf8x00_of_parse_cb, \ 348d3795d63SJagan Teki .n_voltages = ARRAY_SIZE(voltages), \ 349d3795d63SJagan Teki .ops = &pf8x00_buck_ops, \ 350d3795d63SJagan Teki .type = REGULATOR_VOLTAGE, \ 351d3795d63SJagan Teki .id = PF8X00_BUCK ## _id, \ 352d3795d63SJagan Teki .owner = THIS_MODULE, \ 353d3795d63SJagan Teki .volt_table = voltages, \ 354d3795d63SJagan Teki .vsel_reg = (base) + SW_RUN_VOLT, \ 355d3795d63SJagan Teki .vsel_mask = 0xff, \ 356*245f5f65SAdrien Grassein .curr_table = pf8x00_sw_current_table, \ 357*245f5f65SAdrien Grassein .n_current_limits = \ 358*245f5f65SAdrien Grassein ARRAY_SIZE(pf8x00_sw_current_table), \ 359*245f5f65SAdrien Grassein .csel_reg = (base) + SW_CONFIG2, \ 360*245f5f65SAdrien Grassein .csel_mask = PF8X00_SWXILIM_MASK, \ 361d3795d63SJagan Teki .enable_reg = (base) + SW_MODE1, \ 362d3795d63SJagan Teki .enable_val = 0x3, \ 363d3795d63SJagan Teki .disable_val = 0x0, \ 364d3795d63SJagan Teki .enable_mask = 0x3, \ 365d3795d63SJagan Teki .enable_time = 500, \ 366d3795d63SJagan Teki }, \ 367d3795d63SJagan Teki } 368d3795d63SJagan Teki 369d3795d63SJagan Teki #define PF8X00VSNVS(_name, base, voltages) \ 370d3795d63SJagan Teki [PF8X00_VSNVS] = { \ 371d3795d63SJagan Teki .desc = { \ 372d3795d63SJagan Teki .name = _name, \ 373d3795d63SJagan Teki .of_match = _name, \ 374d3795d63SJagan Teki .regulators_node = "regulators", \ 375d3795d63SJagan Teki .n_voltages = ARRAY_SIZE(voltages), \ 376d3795d63SJagan Teki .ops = &pf8x00_vsnvs_ops, \ 377d3795d63SJagan Teki .type = REGULATOR_VOLTAGE, \ 378d3795d63SJagan Teki .id = PF8X00_VSNVS, \ 379d3795d63SJagan Teki .owner = THIS_MODULE, \ 380d3795d63SJagan Teki .volt_table = voltages, \ 381d3795d63SJagan Teki .vsel_reg = (base), \ 382d3795d63SJagan Teki .vsel_mask = 0x3, \ 383d3795d63SJagan Teki }, \ 384d3795d63SJagan Teki } 385d3795d63SJagan Teki 386d3795d63SJagan Teki static struct pf8x00_regulator pf8x00_regulators_data[PF8X00_MAX_REGULATORS] = { 387d3795d63SJagan Teki PF8X00LDO(1, "ldo1", PF8X00_LDO_BASE(PF8X00_LDO1), pf8x00_ldo_voltages), 388d3795d63SJagan Teki PF8X00LDO(2, "ldo2", PF8X00_LDO_BASE(PF8X00_LDO2), pf8x00_ldo_voltages), 389d3795d63SJagan Teki PF8X00LDO(3, "ldo3", PF8X00_LDO_BASE(PF8X00_LDO3), pf8x00_ldo_voltages), 390d3795d63SJagan Teki PF8X00LDO(4, "ldo4", PF8X00_LDO_BASE(PF8X00_LDO4), pf8x00_ldo_voltages), 391d3795d63SJagan Teki PF8X00BUCK(1, "buck1", PF8X00_SW_BASE(PF8X00_BUCK1), pf8x00_sw1_to_6_voltages), 392d3795d63SJagan Teki PF8X00BUCK(2, "buck2", PF8X00_SW_BASE(PF8X00_BUCK2), pf8x00_sw1_to_6_voltages), 393d3795d63SJagan Teki PF8X00BUCK(3, "buck3", PF8X00_SW_BASE(PF8X00_BUCK3), pf8x00_sw1_to_6_voltages), 394d3795d63SJagan Teki PF8X00BUCK(4, "buck4", PF8X00_SW_BASE(PF8X00_BUCK4), pf8x00_sw1_to_6_voltages), 395d3795d63SJagan Teki PF8X00BUCK(5, "buck5", PF8X00_SW_BASE(PF8X00_BUCK5), pf8x00_sw1_to_6_voltages), 396d3795d63SJagan Teki PF8X00BUCK(6, "buck6", PF8X00_SW_BASE(PF8X00_BUCK6), pf8x00_sw1_to_6_voltages), 397d3795d63SJagan Teki PF8X00BUCK(7, "buck7", PF8X00_SW_BASE(PF8X00_BUCK7), pf8x00_sw7_voltages), 398d3795d63SJagan Teki PF8X00VSNVS("vsnvs", PF8X00_VSNVS_CONFIG1, pf8x00_vsnvs_voltages), 399d3795d63SJagan Teki }; 400d3795d63SJagan Teki 401d3795d63SJagan Teki static int pf8x00_identify(struct pf8x00_chip *chip) 402d3795d63SJagan Teki { 403d3795d63SJagan Teki unsigned int value; 404d3795d63SJagan Teki u8 dev_fam, dev_id; 405d3795d63SJagan Teki const char *name = NULL; 406d3795d63SJagan Teki int ret; 407d3795d63SJagan Teki 408d3795d63SJagan Teki ret = regmap_read(chip->regmap, PF8X00_DEVICEID, &value); 409d3795d63SJagan Teki if (ret) { 410d3795d63SJagan Teki dev_err(chip->dev, "failed to read chip family\n"); 411d3795d63SJagan Teki return ret; 412d3795d63SJagan Teki } 413d3795d63SJagan Teki 414d3795d63SJagan Teki dev_fam = value & PF8X00_DEVICE_FAM_MASK; 415d3795d63SJagan Teki switch (dev_fam) { 416d3795d63SJagan Teki case PF8X00_FAM: 417d3795d63SJagan Teki break; 418d3795d63SJagan Teki default: 419d3795d63SJagan Teki dev_err(chip->dev, 420d3795d63SJagan Teki "Chip 0x%x is not from PF8X00 family\n", dev_fam); 421d3795d63SJagan Teki return ret; 422d3795d63SJagan Teki } 423d3795d63SJagan Teki 424d3795d63SJagan Teki dev_id = value & PF8X00_DEVICE_ID_MASK; 425d3795d63SJagan Teki switch (dev_id) { 426d3795d63SJagan Teki case PF8100: 427d3795d63SJagan Teki name = "PF8100"; 428d3795d63SJagan Teki break; 429d3795d63SJagan Teki case PF8121A: 430d3795d63SJagan Teki name = "PF8121A"; 431d3795d63SJagan Teki break; 432d3795d63SJagan Teki case PF8200: 433d3795d63SJagan Teki name = "PF8100"; 434d3795d63SJagan Teki break; 435d3795d63SJagan Teki default: 436d3795d63SJagan Teki dev_err(chip->dev, "Unknown pf8x00 device id 0x%x\n", dev_id); 437d3795d63SJagan Teki return -ENODEV; 438d3795d63SJagan Teki } 439d3795d63SJagan Teki 440d3795d63SJagan Teki dev_info(chip->dev, "%s PMIC found.\n", name); 441d3795d63SJagan Teki 442d3795d63SJagan Teki return 0; 443d3795d63SJagan Teki } 444d3795d63SJagan Teki 445d3795d63SJagan Teki static int pf8x00_i2c_probe(struct i2c_client *client) 446d3795d63SJagan Teki { 447d3795d63SJagan Teki struct regulator_config config = { NULL, }; 448d3795d63SJagan Teki struct pf8x00_chip *chip; 449d3795d63SJagan Teki int id; 450d3795d63SJagan Teki int ret; 451d3795d63SJagan Teki 452d3795d63SJagan Teki chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 453d3795d63SJagan Teki if (!chip) 454d3795d63SJagan Teki return -ENOMEM; 455d3795d63SJagan Teki 456d3795d63SJagan Teki i2c_set_clientdata(client, chip); 457d3795d63SJagan Teki chip->dev = &client->dev; 458d3795d63SJagan Teki 459d3795d63SJagan Teki chip->regmap = devm_regmap_init_i2c(client, &pf8x00_regmap_config); 460d3795d63SJagan Teki if (IS_ERR(chip->regmap)) { 461d3795d63SJagan Teki ret = PTR_ERR(chip->regmap); 462d3795d63SJagan Teki dev_err(&client->dev, 463d3795d63SJagan Teki "regmap allocation failed with err %d\n", ret); 464d3795d63SJagan Teki return ret; 465d3795d63SJagan Teki } 466d3795d63SJagan Teki 467d3795d63SJagan Teki ret = pf8x00_identify(chip); 468d3795d63SJagan Teki if (ret) 469d3795d63SJagan Teki return ret; 470d3795d63SJagan Teki 471d3795d63SJagan Teki for (id = 0; id < ARRAY_SIZE(pf8x00_regulators_data); id++) { 472d3795d63SJagan Teki struct pf8x00_regulator *data = &pf8x00_regulators_data[id]; 473d3795d63SJagan Teki struct regulator_dev *rdev; 474d3795d63SJagan Teki 475d3795d63SJagan Teki config.dev = chip->dev; 476d3795d63SJagan Teki config.driver_data = chip; 477d3795d63SJagan Teki config.regmap = chip->regmap; 478d3795d63SJagan Teki 479d3795d63SJagan Teki rdev = devm_regulator_register(&client->dev, &data->desc, &config); 480d3795d63SJagan Teki if (IS_ERR(rdev)) { 481d3795d63SJagan Teki dev_err(&client->dev, 482d3795d63SJagan Teki "failed to register %s regulator\n", data->desc.name); 483d3795d63SJagan Teki return PTR_ERR(rdev); 484d3795d63SJagan Teki } 485d3795d63SJagan Teki 486d3795d63SJagan Teki if ((id >= PF8X00_BUCK1) && (id <= PF8X00_BUCK7)) { 487d3795d63SJagan Teki u8 reg = PF8X00_SW_BASE(id) + SW_CONFIG2; 488d3795d63SJagan Teki 489d3795d63SJagan Teki regmap_update_bits(chip->regmap, reg, 490d3795d63SJagan Teki PF8X00_SWXPHASE_MASK, 491d3795d63SJagan Teki data->phase_shift); 492d3795d63SJagan Teki } 493d3795d63SJagan Teki } 494d3795d63SJagan Teki 495d3795d63SJagan Teki return 0; 496d3795d63SJagan Teki } 497d3795d63SJagan Teki 498d3795d63SJagan Teki static const struct of_device_id pf8x00_dt_ids[] = { 499df9716ecSMark Brown { .compatible = "nxp,pf8100",}, 500df9716ecSMark Brown { .compatible = "nxp,pf8121a",}, 501df9716ecSMark Brown { .compatible = "nxp,pf8200",}, 502d3795d63SJagan Teki { } 503d3795d63SJagan Teki }; 504d3795d63SJagan Teki MODULE_DEVICE_TABLE(of, pf8x00_dt_ids); 505d3795d63SJagan Teki 506d3795d63SJagan Teki static const struct i2c_device_id pf8x00_i2c_id[] = { 507df9716ecSMark Brown { "pf8100", 0 }, 508df9716ecSMark Brown { "pf8121a", 0 }, 509df9716ecSMark Brown { "pf8200", 0 }, 510d3795d63SJagan Teki {}, 511d3795d63SJagan Teki }; 512d3795d63SJagan Teki MODULE_DEVICE_TABLE(i2c, pf8x00_i2c_id); 513d3795d63SJagan Teki 514d3795d63SJagan Teki static struct i2c_driver pf8x00_regulator_driver = { 515d3795d63SJagan Teki .id_table = pf8x00_i2c_id, 516d3795d63SJagan Teki .driver = { 517d3795d63SJagan Teki .name = "pf8x00", 518d3795d63SJagan Teki .of_match_table = pf8x00_dt_ids, 519d3795d63SJagan Teki }, 520d3795d63SJagan Teki .probe_new = pf8x00_i2c_probe, 521d3795d63SJagan Teki }; 522d3795d63SJagan Teki module_i2c_driver(pf8x00_regulator_driver); 523d3795d63SJagan Teki 524d3795d63SJagan Teki MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>"); 525d3795d63SJagan Teki MODULE_AUTHOR("Troy Kisky <troy.kisky@boundarydevices.com>"); 526d3795d63SJagan Teki MODULE_DESCRIPTION("Regulator Driver for NXP's PF8100/PF8121A/PF8200 PMIC"); 527d3795d63SJagan Teki MODULE_LICENSE("GPL v2"); 528