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_SHIFT 7 118d3795d63SJagan Teki 119d3795d63SJagan Teki enum pf8x00_devid { 120d3795d63SJagan Teki PF8100 = 0x0, 121d3795d63SJagan Teki PF8121A = BIT(1), 122d3795d63SJagan Teki PF8200 = BIT(3), 123d3795d63SJagan Teki }; 124d3795d63SJagan Teki #define PF8X00_FAM BIT(6) 125d3795d63SJagan Teki #define PF8X00_DEVICE_FAM_MASK GENMASK(7, 4) 126d3795d63SJagan Teki #define PF8X00_DEVICE_ID_MASK GENMASK(3, 0) 127d3795d63SJagan Teki 128d3795d63SJagan Teki struct pf8x00_regulator { 129d3795d63SJagan Teki struct regulator_desc desc; 130d3795d63SJagan Teki }; 131d3795d63SJagan Teki 132d3795d63SJagan Teki struct pf8x00_chip { 133d3795d63SJagan Teki struct regmap *regmap; 134d3795d63SJagan Teki struct device *dev; 135d3795d63SJagan Teki }; 136d3795d63SJagan Teki 137d3795d63SJagan Teki static const struct regmap_config pf8x00_regmap_config = { 138d3795d63SJagan Teki .reg_bits = 8, 139d3795d63SJagan Teki .val_bits = 8, 140d3795d63SJagan Teki .max_register = PF8X00_PAGE_SELECT, 141d3795d63SJagan Teki .cache_type = REGCACHE_RBTREE, 142d3795d63SJagan Teki }; 143d3795d63SJagan Teki 144d3795d63SJagan Teki /* VLDOx output: 1.5V to 5.0V */ 145d3795d63SJagan Teki static const int pf8x00_ldo_voltages[] = { 146d3795d63SJagan Teki 1500000, 1600000, 1800000, 1850000, 2150000, 2500000, 2800000, 3000000, 147d3795d63SJagan Teki 3100000, 3150000, 3200000, 3300000, 3350000, 1650000, 1700000, 5000000, 148d3795d63SJagan Teki }; 149d3795d63SJagan Teki 150245f5f65SAdrien Grassein /* Output: 2.1A to 4.5A */ 151245f5f65SAdrien Grassein static const unsigned int pf8x00_sw_current_table[] = { 152245f5f65SAdrien Grassein 2100000, 2600000, 3000000, 4500000, 153245f5f65SAdrien Grassein }; 154245f5f65SAdrien Grassein 155d3795d63SJagan Teki /* Output: 0.4V to 1.8V */ 15635a93349SAdrien Grassein #define PF8XOO_SW1_6_VOLTAGE_NUM 0xB2 15735a93349SAdrien Grassein static const struct linear_range pf8x00_sw1_to_6_voltages[] = { 15835a93349SAdrien Grassein REGULATOR_LINEAR_RANGE(400000, 0x00, 0xB0, 6250), 15935a93349SAdrien Grassein REGULATOR_LINEAR_RANGE(1800000, 0xB1, 0xB1, 0), 160d3795d63SJagan Teki }; 161d3795d63SJagan Teki 162d3795d63SJagan Teki /* Output: 1.0V to 4.1V */ 163d3795d63SJagan Teki static const int pf8x00_sw7_voltages[] = { 164d3795d63SJagan Teki 1000000, 1100000, 1200000, 1250000, 1300000, 1350000, 1500000, 1600000, 165d3795d63SJagan Teki 1800000, 1850000, 2000000, 2100000, 2150000, 2250000, 2300000, 2400000, 166d3795d63SJagan Teki 2500000, 2800000, 3150000, 3200000, 3250000, 3300000, 3350000, 3400000, 167d3795d63SJagan Teki 3500000, 3800000, 4000000, 4100000, 4100000, 4100000, 4100000, 4100000, 168d3795d63SJagan Teki }; 169d3795d63SJagan Teki 170d3795d63SJagan Teki /* Output: 1.8V, 3.0V, or 3.3V */ 171d3795d63SJagan Teki static const int pf8x00_vsnvs_voltages[] = { 172d3795d63SJagan Teki 0, 1800000, 3000000, 3300000, 173d3795d63SJagan Teki }; 174d3795d63SJagan Teki 175245f5f65SAdrien Grassein static void swxilim_select(struct pf8x00_chip *chip, int id, int ilim) 176d3795d63SJagan Teki { 177d3795d63SJagan Teki u8 ilim_sel; 178245f5f65SAdrien Grassein u8 reg = PF8X00_SW_BASE(id) + SW_CONFIG2; 179d3795d63SJagan Teki 180d3795d63SJagan Teki switch (ilim) { 181d3795d63SJagan Teki case 2100: 182d3795d63SJagan Teki ilim_sel = SWXILIM_2100_MA; 183d3795d63SJagan Teki break; 184d3795d63SJagan Teki case 2600: 185d3795d63SJagan Teki ilim_sel = SWXILIM_2600_MA; 186d3795d63SJagan Teki break; 187d3795d63SJagan Teki case 3000: 188d3795d63SJagan Teki ilim_sel = SWXILIM_3000_MA; 189d3795d63SJagan Teki break; 190d3795d63SJagan Teki case 4500: 191d3795d63SJagan Teki ilim_sel = SWXILIM_4500_MA; 192d3795d63SJagan Teki break; 193d3795d63SJagan Teki default: 194d3795d63SJagan Teki ilim_sel = SWXILIM_2100_MA; 195d3795d63SJagan Teki break; 196d3795d63SJagan Teki } 197d3795d63SJagan Teki 198245f5f65SAdrien Grassein regmap_update_bits(chip->regmap, reg, 199245f5f65SAdrien Grassein PF8X00_SWXILIM_MASK, 200245f5f65SAdrien Grassein ilim_sel << PF8X00_SWXILIM_SHIFT); 201245f5f65SAdrien Grassein } 202245f5f65SAdrien Grassein 203245f5f65SAdrien Grassein static void handle_ilim_property(struct device_node *np, 204245f5f65SAdrien Grassein const struct regulator_desc *desc, 205245f5f65SAdrien Grassein struct regulator_config *config) 206245f5f65SAdrien Grassein { 207245f5f65SAdrien Grassein struct pf8x00_chip *chip = config->driver_data; 208245f5f65SAdrien Grassein int ret; 209245f5f65SAdrien Grassein int val; 210245f5f65SAdrien Grassein 211245f5f65SAdrien Grassein if ((desc->id >= PF8X00_BUCK1) && (desc->id <= PF8X00_BUCK7)) { 212245f5f65SAdrien Grassein ret = of_property_read_u32(np, "nxp,ilim-ma", &val); 213245f5f65SAdrien Grassein if (ret) { 214245f5f65SAdrien Grassein dev_dbg(chip->dev, "unspecified ilim for BUCK%d, use value stored in OTP\n", 215245f5f65SAdrien Grassein desc->id - PF8X00_LDO4); 216245f5f65SAdrien Grassein return; 217245f5f65SAdrien Grassein } 218245f5f65SAdrien Grassein 219245f5f65SAdrien Grassein dev_warn(chip->dev, "nxp,ilim-ma is deprecated, please use regulator-max-microamp\n"); 220245f5f65SAdrien Grassein swxilim_select(chip, desc->id, val); 221245f5f65SAdrien Grassein 222245f5f65SAdrien Grassein } else 223245f5f65SAdrien Grassein dev_warn(chip->dev, "nxp,ilim-ma used with incorrect regulator (%d)\n", desc->id); 224d3795d63SJagan Teki } 225d3795d63SJagan Teki 226*475a5d85SAdrien Grassein static void handle_shift_property(struct device_node *np, 227*475a5d85SAdrien Grassein const struct regulator_desc *desc, 228*475a5d85SAdrien Grassein struct regulator_config *config) 229*475a5d85SAdrien Grassein { 230*475a5d85SAdrien Grassein unsigned char id = desc->id - PF8X00_LDO4; 231*475a5d85SAdrien Grassein unsigned char reg = PF8X00_SW_BASE(id) + SW_CONFIG2; 232*475a5d85SAdrien Grassein struct pf8x00_chip *chip = config->driver_data; 233*475a5d85SAdrien Grassein 234*475a5d85SAdrien Grassein int phase; 235*475a5d85SAdrien Grassein int val; 236*475a5d85SAdrien Grassein int ret; 237*475a5d85SAdrien Grassein if ((desc->id >= PF8X00_BUCK1) && (desc->id <= PF8X00_BUCK7)) { 238*475a5d85SAdrien Grassein ret = of_property_read_u32(np, "nxp,phase-shift", &val); 239*475a5d85SAdrien Grassein if (ret) { 240*475a5d85SAdrien Grassein dev_dbg(chip->dev, 241*475a5d85SAdrien Grassein "unspecified phase-shift for BUCK%d, using OTP configuration\n", 242*475a5d85SAdrien Grassein id); 243*475a5d85SAdrien Grassein return; 244*475a5d85SAdrien Grassein } 245*475a5d85SAdrien Grassein 246*475a5d85SAdrien Grassein if (val < 0 || val > 315 || val % 45 != 0) { 247*475a5d85SAdrien Grassein dev_warn(config->dev, 248*475a5d85SAdrien Grassein "invalid phase_shift %d for BUCK%d, using OTP configuration\n", 249*475a5d85SAdrien Grassein val, id); 250*475a5d85SAdrien Grassein return; 251*475a5d85SAdrien Grassein } 252*475a5d85SAdrien Grassein 253*475a5d85SAdrien Grassein phase = val / 45; 254*475a5d85SAdrien Grassein 255*475a5d85SAdrien Grassein if (phase >= 1) 256*475a5d85SAdrien Grassein phase -= 1; 257*475a5d85SAdrien Grassein else 258*475a5d85SAdrien Grassein phase = PF8X00_SWXPHASE_SHIFT; 259*475a5d85SAdrien Grassein 260*475a5d85SAdrien Grassein regmap_update_bits(chip->regmap, reg, 261*475a5d85SAdrien Grassein PF8X00_SWXPHASE_MASK, 262*475a5d85SAdrien Grassein phase); 263*475a5d85SAdrien Grassein } else 264*475a5d85SAdrien Grassein dev_warn(chip->dev, "nxp,phase-shift used with incorrect regulator (%d)\n", id); 265*475a5d85SAdrien Grassein 266*475a5d85SAdrien Grassein } 267*475a5d85SAdrien Grassein 268d3795d63SJagan Teki static int pf8x00_of_parse_cb(struct device_node *np, 269d3795d63SJagan Teki const struct regulator_desc *desc, 270d3795d63SJagan Teki struct regulator_config *config) 271d3795d63SJagan Teki { 272d3795d63SJagan Teki 273245f5f65SAdrien Grassein handle_ilim_property(np, desc, config); 274*475a5d85SAdrien Grassein handle_shift_property(np, desc, config); 275d3795d63SJagan Teki 276d3795d63SJagan Teki return 0; 277d3795d63SJagan Teki } 278d3795d63SJagan Teki 279d3795d63SJagan Teki static const struct regulator_ops pf8x00_ldo_ops = { 280d3795d63SJagan Teki .enable = regulator_enable_regmap, 281d3795d63SJagan Teki .disable = regulator_disable_regmap, 282d3795d63SJagan Teki .is_enabled = regulator_is_enabled_regmap, 283d3795d63SJagan Teki .list_voltage = regulator_list_voltage_table, 284d3795d63SJagan Teki .set_voltage_sel = regulator_set_voltage_sel_regmap, 285d3795d63SJagan Teki .get_voltage_sel = regulator_get_voltage_sel_regmap, 286d3795d63SJagan Teki }; 287d3795d63SJagan Teki 28835a93349SAdrien Grassein 28935a93349SAdrien Grassein static const struct regulator_ops pf8x00_buck1_6_ops = { 29035a93349SAdrien Grassein .enable = regulator_enable_regmap, 29135a93349SAdrien Grassein .disable = regulator_disable_regmap, 29235a93349SAdrien Grassein .is_enabled = regulator_is_enabled_regmap, 29335a93349SAdrien Grassein .list_voltage = regulator_list_voltage_linear_range, 29435a93349SAdrien Grassein .set_voltage_sel = regulator_set_voltage_sel_regmap, 29535a93349SAdrien Grassein .get_voltage_sel = regulator_get_voltage_sel_regmap, 29635a93349SAdrien Grassein .get_current_limit = regulator_get_current_limit_regmap, 29735a93349SAdrien Grassein .set_current_limit = regulator_set_current_limit_regmap, 29835a93349SAdrien Grassein }; 29935a93349SAdrien Grassein 30035a93349SAdrien Grassein static const struct regulator_ops pf8x00_buck7_ops = { 301d3795d63SJagan Teki .enable = regulator_enable_regmap, 302d3795d63SJagan Teki .disable = regulator_disable_regmap, 303d3795d63SJagan Teki .is_enabled = regulator_is_enabled_regmap, 304d3795d63SJagan Teki .list_voltage = regulator_list_voltage_table, 305d3795d63SJagan Teki .set_voltage_sel = regulator_set_voltage_sel_regmap, 306d3795d63SJagan Teki .get_voltage_sel = regulator_get_voltage_sel_regmap, 307245f5f65SAdrien Grassein .get_current_limit = regulator_get_current_limit_regmap, 308245f5f65SAdrien Grassein .set_current_limit = regulator_set_current_limit_regmap, 309d3795d63SJagan Teki }; 310d3795d63SJagan Teki 311d3795d63SJagan Teki static const struct regulator_ops pf8x00_vsnvs_ops = { 312d3795d63SJagan Teki .enable = regulator_enable_regmap, 313d3795d63SJagan Teki .disable = regulator_disable_regmap, 314d3795d63SJagan Teki .is_enabled = regulator_is_enabled_regmap, 315d3795d63SJagan Teki .list_voltage = regulator_list_voltage_table, 316d3795d63SJagan Teki .map_voltage = regulator_map_voltage_ascend, 317d3795d63SJagan Teki .set_voltage_sel = regulator_set_voltage_sel_regmap, 318d3795d63SJagan Teki .get_voltage_sel = regulator_get_voltage_sel_regmap, 319d3795d63SJagan Teki }; 320d3795d63SJagan Teki 321d3795d63SJagan Teki #define PF8X00LDO(_id, _name, base, voltages) \ 322d3795d63SJagan Teki [PF8X00_LDO ## _id] = { \ 323d3795d63SJagan Teki .desc = { \ 324d3795d63SJagan Teki .name = _name, \ 325d3795d63SJagan Teki .of_match = _name, \ 326d3795d63SJagan Teki .regulators_node = "regulators", \ 327d3795d63SJagan Teki .n_voltages = ARRAY_SIZE(voltages), \ 328d3795d63SJagan Teki .ops = &pf8x00_ldo_ops, \ 329d3795d63SJagan Teki .type = REGULATOR_VOLTAGE, \ 330d3795d63SJagan Teki .id = PF8X00_LDO ## _id, \ 331d3795d63SJagan Teki .owner = THIS_MODULE, \ 332d3795d63SJagan Teki .volt_table = voltages, \ 333d3795d63SJagan Teki .vsel_reg = (base) + LDO_RUN_VOLT, \ 334d3795d63SJagan Teki .vsel_mask = 0xff, \ 335d3795d63SJagan Teki .enable_reg = (base) + LDO_CONFIG2, \ 336d3795d63SJagan Teki .enable_val = 0x2, \ 337d3795d63SJagan Teki .disable_val = 0x0, \ 338d3795d63SJagan Teki .enable_mask = 2, \ 339d3795d63SJagan Teki }, \ 340d3795d63SJagan Teki } 341d3795d63SJagan Teki 342d3795d63SJagan Teki #define PF8X00BUCK(_id, _name, base, voltages) \ 343d3795d63SJagan Teki [PF8X00_BUCK ## _id] = { \ 344d3795d63SJagan Teki .desc = { \ 345d3795d63SJagan Teki .name = _name, \ 346d3795d63SJagan Teki .of_match = _name, \ 347d3795d63SJagan Teki .regulators_node = "regulators", \ 348d3795d63SJagan Teki .of_parse_cb = pf8x00_of_parse_cb, \ 34935a93349SAdrien Grassein .n_voltages = PF8XOO_SW1_6_VOLTAGE_NUM, \ 35035a93349SAdrien Grassein .ops = &pf8x00_buck1_6_ops, \ 351d3795d63SJagan Teki .type = REGULATOR_VOLTAGE, \ 352d3795d63SJagan Teki .id = PF8X00_BUCK ## _id, \ 353d3795d63SJagan Teki .owner = THIS_MODULE, \ 35435a93349SAdrien Grassein .linear_ranges = pf8x00_sw1_to_6_voltages, \ 35535a93349SAdrien Grassein .n_linear_ranges = \ 35635a93349SAdrien Grassein ARRAY_SIZE(pf8x00_sw1_to_6_voltages), \ 35735a93349SAdrien Grassein .vsel_reg = (base) + SW_RUN_VOLT, \ 35835a93349SAdrien Grassein .vsel_mask = 0xff, \ 35935a93349SAdrien Grassein .curr_table = pf8x00_sw_current_table, \ 36035a93349SAdrien Grassein .n_current_limits = \ 36135a93349SAdrien Grassein ARRAY_SIZE(pf8x00_sw_current_table), \ 36235a93349SAdrien Grassein .csel_reg = (base) + SW_CONFIG2, \ 36335a93349SAdrien Grassein .csel_mask = PF8X00_SWXILIM_MASK, \ 36435a93349SAdrien Grassein .enable_reg = (base) + SW_MODE1, \ 36535a93349SAdrien Grassein .enable_val = 0x3, \ 36635a93349SAdrien Grassein .disable_val = 0x0, \ 36735a93349SAdrien Grassein .enable_mask = 0x3, \ 36835a93349SAdrien Grassein .enable_time = 500, \ 36935a93349SAdrien Grassein }, \ 37035a93349SAdrien Grassein } 37135a93349SAdrien Grassein 37235a93349SAdrien Grassein #define PF8X00BUCK7(_name, base, voltages) \ 37335a93349SAdrien Grassein [PF8X00_BUCK7] = { \ 37435a93349SAdrien Grassein .desc = { \ 37535a93349SAdrien Grassein .name = _name, \ 37635a93349SAdrien Grassein .of_match = _name, \ 37735a93349SAdrien Grassein .regulators_node = "regulators", \ 37835a93349SAdrien Grassein .of_parse_cb = pf8x00_of_parse_cb, \ 37935a93349SAdrien Grassein .n_voltages = ARRAY_SIZE(voltages), \ 38035a93349SAdrien Grassein .ops = &pf8x00_buck7_ops, \ 38135a93349SAdrien Grassein .type = REGULATOR_VOLTAGE, \ 38235a93349SAdrien Grassein .id = PF8X00_BUCK7, \ 38335a93349SAdrien Grassein .owner = THIS_MODULE, \ 384d3795d63SJagan Teki .volt_table = voltages, \ 385d3795d63SJagan Teki .vsel_reg = (base) + SW_RUN_VOLT, \ 386d3795d63SJagan Teki .vsel_mask = 0xff, \ 387245f5f65SAdrien Grassein .curr_table = pf8x00_sw_current_table, \ 388245f5f65SAdrien Grassein .n_current_limits = \ 389245f5f65SAdrien Grassein ARRAY_SIZE(pf8x00_sw_current_table), \ 390245f5f65SAdrien Grassein .csel_reg = (base) + SW_CONFIG2, \ 391245f5f65SAdrien Grassein .csel_mask = PF8X00_SWXILIM_MASK, \ 392d3795d63SJagan Teki .enable_reg = (base) + SW_MODE1, \ 393d3795d63SJagan Teki .enable_val = 0x3, \ 394d3795d63SJagan Teki .disable_val = 0x0, \ 395d3795d63SJagan Teki .enable_mask = 0x3, \ 396d3795d63SJagan Teki .enable_time = 500, \ 397d3795d63SJagan Teki }, \ 398d3795d63SJagan Teki } 399d3795d63SJagan Teki 40035a93349SAdrien Grassein 401d3795d63SJagan Teki #define PF8X00VSNVS(_name, base, voltages) \ 402d3795d63SJagan Teki [PF8X00_VSNVS] = { \ 403d3795d63SJagan Teki .desc = { \ 404d3795d63SJagan Teki .name = _name, \ 405d3795d63SJagan Teki .of_match = _name, \ 406d3795d63SJagan Teki .regulators_node = "regulators", \ 407d3795d63SJagan Teki .n_voltages = ARRAY_SIZE(voltages), \ 408d3795d63SJagan Teki .ops = &pf8x00_vsnvs_ops, \ 409d3795d63SJagan Teki .type = REGULATOR_VOLTAGE, \ 410d3795d63SJagan Teki .id = PF8X00_VSNVS, \ 411d3795d63SJagan Teki .owner = THIS_MODULE, \ 412d3795d63SJagan Teki .volt_table = voltages, \ 413d3795d63SJagan Teki .vsel_reg = (base), \ 414d3795d63SJagan Teki .vsel_mask = 0x3, \ 415d3795d63SJagan Teki }, \ 416d3795d63SJagan Teki } 417d3795d63SJagan Teki 418d3795d63SJagan Teki static struct pf8x00_regulator pf8x00_regulators_data[PF8X00_MAX_REGULATORS] = { 419d3795d63SJagan Teki PF8X00LDO(1, "ldo1", PF8X00_LDO_BASE(PF8X00_LDO1), pf8x00_ldo_voltages), 420d3795d63SJagan Teki PF8X00LDO(2, "ldo2", PF8X00_LDO_BASE(PF8X00_LDO2), pf8x00_ldo_voltages), 421d3795d63SJagan Teki PF8X00LDO(3, "ldo3", PF8X00_LDO_BASE(PF8X00_LDO3), pf8x00_ldo_voltages), 422d3795d63SJagan Teki PF8X00LDO(4, "ldo4", PF8X00_LDO_BASE(PF8X00_LDO4), pf8x00_ldo_voltages), 423d3795d63SJagan Teki PF8X00BUCK(1, "buck1", PF8X00_SW_BASE(PF8X00_BUCK1), pf8x00_sw1_to_6_voltages), 424d3795d63SJagan Teki PF8X00BUCK(2, "buck2", PF8X00_SW_BASE(PF8X00_BUCK2), pf8x00_sw1_to_6_voltages), 425d3795d63SJagan Teki PF8X00BUCK(3, "buck3", PF8X00_SW_BASE(PF8X00_BUCK3), pf8x00_sw1_to_6_voltages), 426d3795d63SJagan Teki PF8X00BUCK(4, "buck4", PF8X00_SW_BASE(PF8X00_BUCK4), pf8x00_sw1_to_6_voltages), 427d3795d63SJagan Teki PF8X00BUCK(5, "buck5", PF8X00_SW_BASE(PF8X00_BUCK5), pf8x00_sw1_to_6_voltages), 428d3795d63SJagan Teki PF8X00BUCK(6, "buck6", PF8X00_SW_BASE(PF8X00_BUCK6), pf8x00_sw1_to_6_voltages), 42935a93349SAdrien Grassein PF8X00BUCK7("buck7", PF8X00_SW_BASE(PF8X00_BUCK7), pf8x00_sw7_voltages), 430d3795d63SJagan Teki PF8X00VSNVS("vsnvs", PF8X00_VSNVS_CONFIG1, pf8x00_vsnvs_voltages), 431d3795d63SJagan Teki }; 432d3795d63SJagan Teki 433d3795d63SJagan Teki static int pf8x00_identify(struct pf8x00_chip *chip) 434d3795d63SJagan Teki { 435d3795d63SJagan Teki unsigned int value; 436d3795d63SJagan Teki u8 dev_fam, dev_id; 437d3795d63SJagan Teki const char *name = NULL; 438d3795d63SJagan Teki int ret; 439d3795d63SJagan Teki 440d3795d63SJagan Teki ret = regmap_read(chip->regmap, PF8X00_DEVICEID, &value); 441d3795d63SJagan Teki if (ret) { 442d3795d63SJagan Teki dev_err(chip->dev, "failed to read chip family\n"); 443d3795d63SJagan Teki return ret; 444d3795d63SJagan Teki } 445d3795d63SJagan Teki 446d3795d63SJagan Teki dev_fam = value & PF8X00_DEVICE_FAM_MASK; 447d3795d63SJagan Teki switch (dev_fam) { 448d3795d63SJagan Teki case PF8X00_FAM: 449d3795d63SJagan Teki break; 450d3795d63SJagan Teki default: 451d3795d63SJagan Teki dev_err(chip->dev, 452d3795d63SJagan Teki "Chip 0x%x is not from PF8X00 family\n", dev_fam); 453d3795d63SJagan Teki return ret; 454d3795d63SJagan Teki } 455d3795d63SJagan Teki 456d3795d63SJagan Teki dev_id = value & PF8X00_DEVICE_ID_MASK; 457d3795d63SJagan Teki switch (dev_id) { 458d3795d63SJagan Teki case PF8100: 459d3795d63SJagan Teki name = "PF8100"; 460d3795d63SJagan Teki break; 461d3795d63SJagan Teki case PF8121A: 462d3795d63SJagan Teki name = "PF8121A"; 463d3795d63SJagan Teki break; 464d3795d63SJagan Teki case PF8200: 465d3795d63SJagan Teki name = "PF8100"; 466d3795d63SJagan Teki break; 467d3795d63SJagan Teki default: 468d3795d63SJagan Teki dev_err(chip->dev, "Unknown pf8x00 device id 0x%x\n", dev_id); 469d3795d63SJagan Teki return -ENODEV; 470d3795d63SJagan Teki } 471d3795d63SJagan Teki 472d3795d63SJagan Teki dev_info(chip->dev, "%s PMIC found.\n", name); 473d3795d63SJagan Teki 474d3795d63SJagan Teki return 0; 475d3795d63SJagan Teki } 476d3795d63SJagan Teki 477d3795d63SJagan Teki static int pf8x00_i2c_probe(struct i2c_client *client) 478d3795d63SJagan Teki { 479d3795d63SJagan Teki struct regulator_config config = { NULL, }; 480d3795d63SJagan Teki struct pf8x00_chip *chip; 481d3795d63SJagan Teki int id; 482d3795d63SJagan Teki int ret; 483d3795d63SJagan Teki 484d3795d63SJagan Teki chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 485d3795d63SJagan Teki if (!chip) 486d3795d63SJagan Teki return -ENOMEM; 487d3795d63SJagan Teki 488d3795d63SJagan Teki i2c_set_clientdata(client, chip); 489d3795d63SJagan Teki chip->dev = &client->dev; 490d3795d63SJagan Teki 491d3795d63SJagan Teki chip->regmap = devm_regmap_init_i2c(client, &pf8x00_regmap_config); 492d3795d63SJagan Teki if (IS_ERR(chip->regmap)) { 493d3795d63SJagan Teki ret = PTR_ERR(chip->regmap); 494d3795d63SJagan Teki dev_err(&client->dev, 495d3795d63SJagan Teki "regmap allocation failed with err %d\n", ret); 496d3795d63SJagan Teki return ret; 497d3795d63SJagan Teki } 498d3795d63SJagan Teki 499d3795d63SJagan Teki ret = pf8x00_identify(chip); 500d3795d63SJagan Teki if (ret) 501d3795d63SJagan Teki return ret; 502d3795d63SJagan Teki 503d3795d63SJagan Teki for (id = 0; id < ARRAY_SIZE(pf8x00_regulators_data); id++) { 504d3795d63SJagan Teki struct pf8x00_regulator *data = &pf8x00_regulators_data[id]; 505d3795d63SJagan Teki struct regulator_dev *rdev; 506d3795d63SJagan Teki 507d3795d63SJagan Teki config.dev = chip->dev; 508d3795d63SJagan Teki config.driver_data = chip; 509d3795d63SJagan Teki config.regmap = chip->regmap; 510d3795d63SJagan Teki 511d3795d63SJagan Teki rdev = devm_regulator_register(&client->dev, &data->desc, &config); 512d3795d63SJagan Teki if (IS_ERR(rdev)) { 513d3795d63SJagan Teki dev_err(&client->dev, 514d3795d63SJagan Teki "failed to register %s regulator\n", data->desc.name); 515d3795d63SJagan Teki return PTR_ERR(rdev); 516d3795d63SJagan Teki } 517d3795d63SJagan Teki } 518d3795d63SJagan Teki 519d3795d63SJagan Teki return 0; 520d3795d63SJagan Teki } 521d3795d63SJagan Teki 522d3795d63SJagan Teki static const struct of_device_id pf8x00_dt_ids[] = { 523df9716ecSMark Brown { .compatible = "nxp,pf8100",}, 524df9716ecSMark Brown { .compatible = "nxp,pf8121a",}, 525df9716ecSMark Brown { .compatible = "nxp,pf8200",}, 526d3795d63SJagan Teki { } 527d3795d63SJagan Teki }; 528d3795d63SJagan Teki MODULE_DEVICE_TABLE(of, pf8x00_dt_ids); 529d3795d63SJagan Teki 530d3795d63SJagan Teki static const struct i2c_device_id pf8x00_i2c_id[] = { 531df9716ecSMark Brown { "pf8100", 0 }, 532df9716ecSMark Brown { "pf8121a", 0 }, 533df9716ecSMark Brown { "pf8200", 0 }, 534d3795d63SJagan Teki {}, 535d3795d63SJagan Teki }; 536d3795d63SJagan Teki MODULE_DEVICE_TABLE(i2c, pf8x00_i2c_id); 537d3795d63SJagan Teki 538d3795d63SJagan Teki static struct i2c_driver pf8x00_regulator_driver = { 539d3795d63SJagan Teki .id_table = pf8x00_i2c_id, 540d3795d63SJagan Teki .driver = { 541d3795d63SJagan Teki .name = "pf8x00", 542d3795d63SJagan Teki .of_match_table = pf8x00_dt_ids, 543d3795d63SJagan Teki }, 544d3795d63SJagan Teki .probe_new = pf8x00_i2c_probe, 545d3795d63SJagan Teki }; 546d3795d63SJagan Teki module_i2c_driver(pf8x00_regulator_driver); 547d3795d63SJagan Teki 548d3795d63SJagan Teki MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>"); 549d3795d63SJagan Teki MODULE_AUTHOR("Troy Kisky <troy.kisky@boundarydevices.com>"); 550d3795d63SJagan Teki MODULE_DESCRIPTION("Regulator Driver for NXP's PF8100/PF8121A/PF8200 PMIC"); 551d3795d63SJagan Teki MODULE_LICENSE("GPL v2"); 552