1760423dfSChiYuan Huang // SPDX-License-Identifier: GPL-2.0+ 2760423dfSChiYuan Huang 3760423dfSChiYuan Huang #include <dt-bindings/regulator/richtek,rt5190a-regulator.h> 4760423dfSChiYuan Huang #include <linux/bits.h> 5760423dfSChiYuan Huang #include <linux/i2c.h> 6760423dfSChiYuan Huang #include <linux/interrupt.h> 7760423dfSChiYuan Huang #include <linux/kernel.h> 8760423dfSChiYuan Huang #include <linux/module.h> 9760423dfSChiYuan Huang #include <linux/of.h> 10760423dfSChiYuan Huang #include <linux/property.h> 11760423dfSChiYuan Huang #include <linux/regmap.h> 12760423dfSChiYuan Huang #include <linux/regulator/driver.h> 13760423dfSChiYuan Huang #include <linux/regulator/machine.h> 14760423dfSChiYuan Huang #include <linux/regulator/of_regulator.h> 15760423dfSChiYuan Huang 16760423dfSChiYuan Huang #define RT5190A_REG_MANUFACTURE 0x00 17760423dfSChiYuan Huang #define RT5190A_REG_BUCK2VSEL 0x04 18760423dfSChiYuan Huang #define RT5190A_REG_BUCK3VSEL 0x05 19760423dfSChiYuan Huang #define RT5190A_REG_DCDCCNTL 0x06 20760423dfSChiYuan Huang #define RT5190A_REG_ENABLE 0x07 21760423dfSChiYuan Huang #define RT5190A_REG_DISCHARGE 0x09 22760423dfSChiYuan Huang #define RT5190A_REG_PROTMODE 0x0A 23760423dfSChiYuan Huang #define RT5190A_REG_MUTECNTL 0x0B 24760423dfSChiYuan Huang #define RT5190A_REG_PGSTAT 0x0F 25760423dfSChiYuan Huang #define RT5190A_REG_OVINT 0x10 26760423dfSChiYuan Huang #define RT5190A_REG_HOTDIEMASK 0x17 27760423dfSChiYuan Huang 28760423dfSChiYuan Huang #define RT5190A_VSEL_MASK GENMASK(6, 0) 29760423dfSChiYuan Huang #define RT5190A_RID_BITMASK(rid) BIT(rid + 1) 30760423dfSChiYuan Huang #define RT5190A_BUCK1_DISCHG_MASK GENMASK(1, 0) 31760423dfSChiYuan Huang #define RT5190A_BUCK1_DISCHG_ONVAL 0x01 32760423dfSChiYuan Huang #define RT5190A_OVERVOLT_MASK GENMASK(7, 0) 33760423dfSChiYuan Huang #define RT5190A_UNDERVOLT_MASK GENMASK(15, 8) 34760423dfSChiYuan Huang #define RT5190A_CH234OT_MASK BIT(29) 35760423dfSChiYuan Huang #define RT5190A_CHIPOT_MASK BIT(28) 36760423dfSChiYuan Huang 37760423dfSChiYuan Huang #define RT5190A_BUCK23_MINUV 600000 38760423dfSChiYuan Huang #define RT5190A_BUCK23_MAXUV 1400000 39760423dfSChiYuan Huang #define RT5190A_BUCK23_STEPUV 10000 40760423dfSChiYuan Huang #define RT5190A_BUCK23_STEPNUM ((1400000 - 600000) / 10000 + 1) 41760423dfSChiYuan Huang 42760423dfSChiYuan Huang enum { 43760423dfSChiYuan Huang RT5190A_IDX_BUCK1 = 0, 44760423dfSChiYuan Huang RT5190A_IDX_BUCK2, 45760423dfSChiYuan Huang RT5190A_IDX_BUCK3, 46760423dfSChiYuan Huang RT5190A_IDX_BUCK4, 47760423dfSChiYuan Huang RT5190A_IDX_LDO, 48760423dfSChiYuan Huang RT5190A_MAX_IDX 49760423dfSChiYuan Huang }; 50760423dfSChiYuan Huang 51760423dfSChiYuan Huang struct rt5190a_priv { 52760423dfSChiYuan Huang struct device *dev; 53760423dfSChiYuan Huang struct regmap *regmap; 54760423dfSChiYuan Huang struct regulator_desc rdesc[RT5190A_MAX_IDX]; 55760423dfSChiYuan Huang struct regulator_dev *rdev[RT5190A_MAX_IDX]; 56760423dfSChiYuan Huang }; 57760423dfSChiYuan Huang 58760423dfSChiYuan Huang static int rt5190a_get_error_flags(struct regulator_dev *rdev, 59760423dfSChiYuan Huang unsigned int *flags) 60760423dfSChiYuan Huang { 61760423dfSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 62760423dfSChiYuan Huang int rid = rdev_get_id(rdev); 63760423dfSChiYuan Huang unsigned int pgood_stat; 64760423dfSChiYuan Huang int ret; 65760423dfSChiYuan Huang 66760423dfSChiYuan Huang ret = regmap_read(regmap, RT5190A_REG_PGSTAT, &pgood_stat); 67760423dfSChiYuan Huang if (ret) 68760423dfSChiYuan Huang return ret; 69760423dfSChiYuan Huang 70760423dfSChiYuan Huang if (!(pgood_stat & RT5190A_RID_BITMASK(rid))) 71760423dfSChiYuan Huang *flags = REGULATOR_ERROR_FAIL; 72760423dfSChiYuan Huang else 73760423dfSChiYuan Huang *flags = 0; 74760423dfSChiYuan Huang 75760423dfSChiYuan Huang return 0; 76760423dfSChiYuan Huang } 77760423dfSChiYuan Huang 78760423dfSChiYuan Huang static int rt5190a_fixed_buck_set_mode(struct regulator_dev *rdev, 79760423dfSChiYuan Huang unsigned int mode) 80760423dfSChiYuan Huang { 81760423dfSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 82760423dfSChiYuan Huang int rid = rdev_get_id(rdev); 83760423dfSChiYuan Huang unsigned int mask = RT5190A_RID_BITMASK(rid), val; 84760423dfSChiYuan Huang 85760423dfSChiYuan Huang switch (mode) { 86760423dfSChiYuan Huang case REGULATOR_MODE_FAST: 87760423dfSChiYuan Huang val = mask; 88760423dfSChiYuan Huang break; 89760423dfSChiYuan Huang case REGULATOR_MODE_NORMAL: 90760423dfSChiYuan Huang val = 0; 91760423dfSChiYuan Huang break; 92760423dfSChiYuan Huang default: 93760423dfSChiYuan Huang return -EINVAL; 94760423dfSChiYuan Huang } 95760423dfSChiYuan Huang 96760423dfSChiYuan Huang return regmap_update_bits(regmap, RT5190A_REG_DCDCCNTL, mask, val); 97760423dfSChiYuan Huang } 98760423dfSChiYuan Huang 99760423dfSChiYuan Huang static unsigned int rt5190a_fixed_buck_get_mode(struct regulator_dev *rdev) 100760423dfSChiYuan Huang { 101760423dfSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 102760423dfSChiYuan Huang int rid = rdev_get_id(rdev); 103760423dfSChiYuan Huang unsigned int val; 104760423dfSChiYuan Huang int ret; 105760423dfSChiYuan Huang 106760423dfSChiYuan Huang ret = regmap_read(regmap, RT5190A_REG_DCDCCNTL, &val); 107760423dfSChiYuan Huang if (ret) { 108760423dfSChiYuan Huang dev_err(&rdev->dev, "Failed to get mode [%d]\n", ret); 109760423dfSChiYuan Huang return ret; 110760423dfSChiYuan Huang } 111760423dfSChiYuan Huang 112760423dfSChiYuan Huang if (val & RT5190A_RID_BITMASK(rid)) 113760423dfSChiYuan Huang return REGULATOR_MODE_FAST; 114760423dfSChiYuan Huang 115760423dfSChiYuan Huang return REGULATOR_MODE_NORMAL; 116760423dfSChiYuan Huang } 117760423dfSChiYuan Huang 118760423dfSChiYuan Huang static const struct regulator_ops rt5190a_ranged_buck_ops = { 119760423dfSChiYuan Huang .enable = regulator_enable_regmap, 120760423dfSChiYuan Huang .disable = regulator_disable_regmap, 121760423dfSChiYuan Huang .is_enabled = regulator_is_enabled_regmap, 122760423dfSChiYuan Huang .set_voltage_sel = regulator_set_voltage_sel_regmap, 123760423dfSChiYuan Huang .get_voltage_sel = regulator_get_voltage_sel_regmap, 124760423dfSChiYuan Huang .list_voltage = regulator_list_voltage_linear, 125760423dfSChiYuan Huang .set_active_discharge = regulator_set_active_discharge_regmap, 126760423dfSChiYuan Huang .get_error_flags = rt5190a_get_error_flags, 127760423dfSChiYuan Huang }; 128760423dfSChiYuan Huang 129760423dfSChiYuan Huang static const struct regulator_ops rt5190a_fixed_buck_ops = { 130760423dfSChiYuan Huang .enable = regulator_enable_regmap, 131760423dfSChiYuan Huang .disable = regulator_disable_regmap, 132760423dfSChiYuan Huang .is_enabled = regulator_is_enabled_regmap, 133760423dfSChiYuan Huang .set_active_discharge = regulator_set_active_discharge_regmap, 134760423dfSChiYuan Huang .set_mode = rt5190a_fixed_buck_set_mode, 135760423dfSChiYuan Huang .get_mode = rt5190a_fixed_buck_get_mode, 136760423dfSChiYuan Huang .get_error_flags = rt5190a_get_error_flags, 137760423dfSChiYuan Huang }; 138760423dfSChiYuan Huang 139760423dfSChiYuan Huang static const struct regulator_ops rt5190a_fixed_ldo_ops = { 140760423dfSChiYuan Huang .enable = regulator_enable_regmap, 141760423dfSChiYuan Huang .disable = regulator_disable_regmap, 142760423dfSChiYuan Huang .is_enabled = regulator_is_enabled_regmap, 143760423dfSChiYuan Huang .set_active_discharge = regulator_set_active_discharge_regmap, 144760423dfSChiYuan Huang .get_error_flags = rt5190a_get_error_flags, 145760423dfSChiYuan Huang }; 146760423dfSChiYuan Huang 147760423dfSChiYuan Huang static irqreturn_t rt5190a_irq_handler(int irq, void *data) 148760423dfSChiYuan Huang { 149760423dfSChiYuan Huang struct rt5190a_priv *priv = data; 150760423dfSChiYuan Huang __le32 raws; 151760423dfSChiYuan Huang unsigned int events, fields; 152760423dfSChiYuan Huang static const struct { 153760423dfSChiYuan Huang unsigned int bitmask; 154760423dfSChiYuan Huang unsigned int report; 155760423dfSChiYuan Huang } event_tbl[] = { 156760423dfSChiYuan Huang { RT5190A_OVERVOLT_MASK, REGULATOR_ERROR_REGULATION_OUT }, 157760423dfSChiYuan Huang { RT5190A_UNDERVOLT_MASK, REGULATOR_ERROR_UNDER_VOLTAGE } 158760423dfSChiYuan Huang }; 159760423dfSChiYuan Huang int i, j, ret; 160760423dfSChiYuan Huang 161760423dfSChiYuan Huang ret = regmap_raw_read(priv->regmap, RT5190A_REG_OVINT, &raws, 162760423dfSChiYuan Huang sizeof(raws)); 163760423dfSChiYuan Huang if (ret) { 164760423dfSChiYuan Huang dev_err(priv->dev, "Failed to read events\n"); 165760423dfSChiYuan Huang return IRQ_NONE; 166760423dfSChiYuan Huang } 167760423dfSChiYuan Huang 168760423dfSChiYuan Huang events = le32_to_cpu(raws); 169760423dfSChiYuan Huang 170760423dfSChiYuan Huang ret = regmap_raw_write(priv->regmap, RT5190A_REG_OVINT, &raws, 171760423dfSChiYuan Huang sizeof(raws)); 172760423dfSChiYuan Huang if (ret) 173760423dfSChiYuan Huang dev_err(priv->dev, "Failed to write-clear events\n"); 174760423dfSChiYuan Huang 175760423dfSChiYuan Huang /* Handle OV,UV events */ 176760423dfSChiYuan Huang for (i = 0; i < ARRAY_SIZE(event_tbl); i++) { 177760423dfSChiYuan Huang fields = events & event_tbl[i].bitmask; 178760423dfSChiYuan Huang fields >>= ffs(event_tbl[i].bitmask) - 1; 179760423dfSChiYuan Huang 180760423dfSChiYuan Huang for (j = 0; j < RT5190A_MAX_IDX; j++) { 181760423dfSChiYuan Huang if (!(fields & RT5190A_RID_BITMASK(j))) 182760423dfSChiYuan Huang continue; 183760423dfSChiYuan Huang 184760423dfSChiYuan Huang regulator_notifier_call_chain(priv->rdev[j], 185760423dfSChiYuan Huang event_tbl[i].report, 186760423dfSChiYuan Huang NULL); 187760423dfSChiYuan Huang } 188760423dfSChiYuan Huang } 189760423dfSChiYuan Huang 190760423dfSChiYuan Huang /* Handle CH234 OT event */ 191760423dfSChiYuan Huang if (events & RT5190A_CH234OT_MASK) { 192760423dfSChiYuan Huang for (j = RT5190A_IDX_BUCK2; j < RT5190A_IDX_LDO; j++) { 193760423dfSChiYuan Huang regulator_notifier_call_chain(priv->rdev[j], 194760423dfSChiYuan Huang REGULATOR_ERROR_OVER_TEMP, 195760423dfSChiYuan Huang NULL); 196760423dfSChiYuan Huang } 197760423dfSChiYuan Huang } 198760423dfSChiYuan Huang 199760423dfSChiYuan Huang /* Warning if CHIP OT occur */ 200760423dfSChiYuan Huang if (events & RT5190A_CHIPOT_MASK) 201760423dfSChiYuan Huang dev_warn(priv->dev, "CHIP overheat\n"); 202760423dfSChiYuan Huang 203760423dfSChiYuan Huang return IRQ_HANDLED; 204760423dfSChiYuan Huang } 205760423dfSChiYuan Huang 206760423dfSChiYuan Huang static unsigned int rt5190a_of_map_mode(unsigned int mode) 207760423dfSChiYuan Huang { 208760423dfSChiYuan Huang switch (mode) { 209760423dfSChiYuan Huang case RT5190A_OPMODE_AUTO: 210760423dfSChiYuan Huang return REGULATOR_MODE_NORMAL; 211760423dfSChiYuan Huang case RT5190A_OPMODE_FPWM: 212760423dfSChiYuan Huang return REGULATOR_MODE_FAST; 213760423dfSChiYuan Huang default: 214760423dfSChiYuan Huang return REGULATOR_MODE_INVALID; 215760423dfSChiYuan Huang } 216760423dfSChiYuan Huang } 217760423dfSChiYuan Huang 218760423dfSChiYuan Huang static int rt5190a_of_parse_cb(struct rt5190a_priv *priv, int rid, 219760423dfSChiYuan Huang struct of_regulator_match *match) 220760423dfSChiYuan Huang { 221760423dfSChiYuan Huang struct regulator_desc *desc = priv->rdesc + rid; 222760423dfSChiYuan Huang struct regulator_init_data *init_data = match->init_data; 223760423dfSChiYuan Huang struct device_node *np = match->of_node; 224760423dfSChiYuan Huang bool latchup_enable; 225760423dfSChiYuan Huang unsigned int mask = RT5190A_RID_BITMASK(rid), val; 226760423dfSChiYuan Huang 2275f7202d8SChiYuan Huang if (!init_data) 2285f7202d8SChiYuan Huang return 0; 2295f7202d8SChiYuan Huang 230760423dfSChiYuan Huang switch (rid) { 231760423dfSChiYuan Huang case RT5190A_IDX_BUCK1: 232760423dfSChiYuan Huang case RT5190A_IDX_BUCK4: 233760423dfSChiYuan Huang case RT5190A_IDX_LDO: 234760423dfSChiYuan Huang init_data->constraints.apply_uV = 0; 235760423dfSChiYuan Huang 236760423dfSChiYuan Huang if (init_data->constraints.min_uV == 237760423dfSChiYuan Huang init_data->constraints.max_uV) 238760423dfSChiYuan Huang desc->fixed_uV = init_data->constraints.min_uV; 239760423dfSChiYuan Huang else { 240760423dfSChiYuan Huang dev_err(priv->dev, 241760423dfSChiYuan Huang "Variable voltage for fixed regulator\n"); 242760423dfSChiYuan Huang return -EINVAL; 243760423dfSChiYuan Huang } 244760423dfSChiYuan Huang break; 245760423dfSChiYuan Huang default: 246760423dfSChiYuan Huang break; 247760423dfSChiYuan Huang } 248760423dfSChiYuan Huang 249760423dfSChiYuan Huang latchup_enable = of_property_read_bool(np, "richtek,latchup-enable"); 250760423dfSChiYuan Huang 251760423dfSChiYuan Huang /* latchup: 0, default hiccup: 1 */ 252760423dfSChiYuan Huang val = !latchup_enable ? mask : 0; 253760423dfSChiYuan Huang 254760423dfSChiYuan Huang return regmap_update_bits(priv->regmap, RT5190A_REG_PROTMODE, mask, val); 255760423dfSChiYuan Huang } 256760423dfSChiYuan Huang 257760423dfSChiYuan Huang static void rt5190a_fillin_regulator_desc(struct regulator_desc *desc, int rid) 258760423dfSChiYuan Huang { 259760423dfSChiYuan Huang static const char * const regu_name[] = { "buck1", "buck2", 260760423dfSChiYuan Huang "buck3", "buck4", 261760423dfSChiYuan Huang "ldo" }; 262760423dfSChiYuan Huang static const char * const supply[] = { NULL, "vin2", "vin3", "vin4", 263760423dfSChiYuan Huang "vinldo" }; 264760423dfSChiYuan Huang 265760423dfSChiYuan Huang desc->name = regu_name[rid]; 266760423dfSChiYuan Huang desc->supply_name = supply[rid]; 267760423dfSChiYuan Huang desc->owner = THIS_MODULE; 268760423dfSChiYuan Huang desc->type = REGULATOR_VOLTAGE; 269760423dfSChiYuan Huang desc->id = rid; 270760423dfSChiYuan Huang desc->enable_reg = RT5190A_REG_ENABLE; 271760423dfSChiYuan Huang desc->enable_mask = RT5190A_RID_BITMASK(rid); 272760423dfSChiYuan Huang desc->active_discharge_reg = RT5190A_REG_DISCHARGE; 273760423dfSChiYuan Huang desc->active_discharge_mask = RT5190A_RID_BITMASK(rid); 274760423dfSChiYuan Huang desc->active_discharge_on = RT5190A_RID_BITMASK(rid); 275760423dfSChiYuan Huang 276760423dfSChiYuan Huang switch (rid) { 277760423dfSChiYuan Huang case RT5190A_IDX_BUCK1: 278760423dfSChiYuan Huang desc->active_discharge_mask = RT5190A_BUCK1_DISCHG_MASK; 279760423dfSChiYuan Huang desc->active_discharge_on = RT5190A_BUCK1_DISCHG_ONVAL; 280760423dfSChiYuan Huang desc->n_voltages = 1; 281760423dfSChiYuan Huang desc->ops = &rt5190a_fixed_buck_ops; 282760423dfSChiYuan Huang desc->of_map_mode = rt5190a_of_map_mode; 283760423dfSChiYuan Huang break; 284760423dfSChiYuan Huang case RT5190A_IDX_BUCK2: 285760423dfSChiYuan Huang desc->vsel_reg = RT5190A_REG_BUCK2VSEL; 286760423dfSChiYuan Huang desc->vsel_mask = RT5190A_VSEL_MASK; 287760423dfSChiYuan Huang desc->min_uV = RT5190A_BUCK23_MINUV; 288760423dfSChiYuan Huang desc->uV_step = RT5190A_BUCK23_STEPUV; 289760423dfSChiYuan Huang desc->n_voltages = RT5190A_BUCK23_STEPNUM; 290760423dfSChiYuan Huang desc->ops = &rt5190a_ranged_buck_ops; 291760423dfSChiYuan Huang break; 292760423dfSChiYuan Huang case RT5190A_IDX_BUCK3: 293760423dfSChiYuan Huang desc->vsel_reg = RT5190A_REG_BUCK3VSEL; 294760423dfSChiYuan Huang desc->vsel_mask = RT5190A_VSEL_MASK; 295760423dfSChiYuan Huang desc->min_uV = RT5190A_BUCK23_MINUV; 296760423dfSChiYuan Huang desc->uV_step = RT5190A_BUCK23_STEPUV; 297760423dfSChiYuan Huang desc->n_voltages = RT5190A_BUCK23_STEPNUM; 298760423dfSChiYuan Huang desc->ops = &rt5190a_ranged_buck_ops; 299760423dfSChiYuan Huang break; 300760423dfSChiYuan Huang case RT5190A_IDX_BUCK4: 301760423dfSChiYuan Huang desc->n_voltages = 1; 302760423dfSChiYuan Huang desc->ops = &rt5190a_fixed_buck_ops; 303760423dfSChiYuan Huang desc->of_map_mode = rt5190a_of_map_mode; 304760423dfSChiYuan Huang break; 305760423dfSChiYuan Huang case RT5190A_IDX_LDO: 306760423dfSChiYuan Huang desc->n_voltages = 1; 307760423dfSChiYuan Huang desc->ops = &rt5190a_fixed_ldo_ops; 308760423dfSChiYuan Huang break; 309760423dfSChiYuan Huang } 310760423dfSChiYuan Huang } 311760423dfSChiYuan Huang 312760423dfSChiYuan Huang static struct of_regulator_match rt5190a_regulator_match[] = { 313760423dfSChiYuan Huang { .name = "buck1", }, 314760423dfSChiYuan Huang { .name = "buck2", }, 315760423dfSChiYuan Huang { .name = "buck3", }, 316760423dfSChiYuan Huang { .name = "buck4", }, 317760423dfSChiYuan Huang { .name = "ldo", } 318760423dfSChiYuan Huang }; 319760423dfSChiYuan Huang 320760423dfSChiYuan Huang static int rt5190a_parse_regulator_dt_data(struct rt5190a_priv *priv) 321760423dfSChiYuan Huang { 322760423dfSChiYuan Huang struct device_node *regulator_np; 323760423dfSChiYuan Huang struct regulator_desc *reg_desc; 324760423dfSChiYuan Huang struct of_regulator_match *match; 325760423dfSChiYuan Huang int i, ret; 326760423dfSChiYuan Huang 327760423dfSChiYuan Huang for (i = 0; i < RT5190A_MAX_IDX; i++) { 328760423dfSChiYuan Huang reg_desc = priv->rdesc + i; 329760423dfSChiYuan Huang match = rt5190a_regulator_match + i; 330760423dfSChiYuan Huang 331760423dfSChiYuan Huang rt5190a_fillin_regulator_desc(reg_desc, i); 332760423dfSChiYuan Huang 333760423dfSChiYuan Huang match->desc = reg_desc; 334760423dfSChiYuan Huang } 335760423dfSChiYuan Huang 336760423dfSChiYuan Huang regulator_np = of_get_child_by_name(priv->dev->of_node, "regulators"); 337760423dfSChiYuan Huang if (!regulator_np) { 338760423dfSChiYuan Huang dev_err(priv->dev, "Could not find 'regulators' node\n"); 339760423dfSChiYuan Huang return -ENODEV; 340760423dfSChiYuan Huang } 341760423dfSChiYuan Huang 342760423dfSChiYuan Huang ret = of_regulator_match(priv->dev, regulator_np, 343760423dfSChiYuan Huang rt5190a_regulator_match, 344760423dfSChiYuan Huang ARRAY_SIZE(rt5190a_regulator_match)); 345760423dfSChiYuan Huang 346760423dfSChiYuan Huang of_node_put(regulator_np); 347760423dfSChiYuan Huang 348760423dfSChiYuan Huang if (ret < 0) { 349760423dfSChiYuan Huang dev_err(priv->dev, 350760423dfSChiYuan Huang "Error parsing regulator init data: %d\n", ret); 351760423dfSChiYuan Huang return ret; 352760423dfSChiYuan Huang } 353760423dfSChiYuan Huang 354760423dfSChiYuan Huang for (i = 0; i < RT5190A_MAX_IDX; i++) { 355760423dfSChiYuan Huang match = rt5190a_regulator_match + i; 356760423dfSChiYuan Huang 357760423dfSChiYuan Huang ret = rt5190a_of_parse_cb(priv, i, match); 358760423dfSChiYuan Huang if (ret) { 359760423dfSChiYuan Huang dev_err(priv->dev, "Failed in [%d] of_parse_cb\n", i); 360760423dfSChiYuan Huang return ret; 361760423dfSChiYuan Huang } 362760423dfSChiYuan Huang } 363760423dfSChiYuan Huang 364760423dfSChiYuan Huang return 0; 365760423dfSChiYuan Huang } 366760423dfSChiYuan Huang 367760423dfSChiYuan Huang static const struct reg_sequence rt5190a_init_patch[] = { 368760423dfSChiYuan Huang { 0x09, 0x3d, }, 369760423dfSChiYuan Huang { 0x0a, 0x3e, }, 370760423dfSChiYuan Huang { 0x0b, 0x01, }, 371760423dfSChiYuan Huang { 0x10, 0xff, }, 372760423dfSChiYuan Huang { 0x11, 0xff, }, 373760423dfSChiYuan Huang { 0x12, 0xff, }, 374760423dfSChiYuan Huang { 0x13, 0xff, }, 375760423dfSChiYuan Huang { 0x14, 0, }, 376760423dfSChiYuan Huang { 0x15, 0, }, 377760423dfSChiYuan Huang { 0x16, 0x3e, }, 378760423dfSChiYuan Huang { 0x17, 0, } 379760423dfSChiYuan Huang }; 380760423dfSChiYuan Huang 381760423dfSChiYuan Huang static int rt5190a_device_initialize(struct rt5190a_priv *priv) 382760423dfSChiYuan Huang { 383760423dfSChiYuan Huang bool mute_enable; 384760423dfSChiYuan Huang int ret; 385760423dfSChiYuan Huang 386760423dfSChiYuan Huang ret = regmap_register_patch(priv->regmap, rt5190a_init_patch, 387760423dfSChiYuan Huang ARRAY_SIZE(rt5190a_init_patch)); 388760423dfSChiYuan Huang if (ret) { 389760423dfSChiYuan Huang dev_err(priv->dev, "Failed to do register patch\n"); 390760423dfSChiYuan Huang return ret; 391760423dfSChiYuan Huang } 392760423dfSChiYuan Huang 393760423dfSChiYuan Huang mute_enable = device_property_read_bool(priv->dev, 394760423dfSChiYuan Huang "richtek,mute-enable"); 395760423dfSChiYuan Huang 396760423dfSChiYuan Huang if (mute_enable) { 397760423dfSChiYuan Huang ret = regmap_write(priv->regmap, RT5190A_REG_MUTECNTL, 0x00); 398760423dfSChiYuan Huang if (ret) { 399760423dfSChiYuan Huang dev_err(priv->dev, "Failed to enable mute function\n"); 400760423dfSChiYuan Huang return ret; 401760423dfSChiYuan Huang } 402760423dfSChiYuan Huang } 403760423dfSChiYuan Huang 404760423dfSChiYuan Huang return 0; 405760423dfSChiYuan Huang } 406760423dfSChiYuan Huang 407760423dfSChiYuan Huang static int rt5190a_device_check(struct rt5190a_priv *priv) 408760423dfSChiYuan Huang { 409760423dfSChiYuan Huang u16 devid; 410760423dfSChiYuan Huang int ret; 411760423dfSChiYuan Huang 412760423dfSChiYuan Huang ret = regmap_raw_read(priv->regmap, RT5190A_REG_MANUFACTURE, &devid, 413760423dfSChiYuan Huang sizeof(devid)); 414760423dfSChiYuan Huang if (ret) 415760423dfSChiYuan Huang return ret; 416760423dfSChiYuan Huang 417760423dfSChiYuan Huang if (devid) { 418760423dfSChiYuan Huang dev_err(priv->dev, "Incorrect device id 0x%04x\n", devid); 419760423dfSChiYuan Huang return -ENODEV; 420760423dfSChiYuan Huang } 421760423dfSChiYuan Huang 422760423dfSChiYuan Huang return 0; 423760423dfSChiYuan Huang } 424760423dfSChiYuan Huang 425760423dfSChiYuan Huang static const struct regmap_config rt5190a_regmap_config = { 426760423dfSChiYuan Huang .reg_bits = 8, 427760423dfSChiYuan Huang .val_bits = 8, 428760423dfSChiYuan Huang .max_register = RT5190A_REG_HOTDIEMASK, 429760423dfSChiYuan Huang }; 430760423dfSChiYuan Huang 431760423dfSChiYuan Huang static int rt5190a_probe(struct i2c_client *i2c) 432760423dfSChiYuan Huang { 433760423dfSChiYuan Huang struct rt5190a_priv *priv; 434760423dfSChiYuan Huang struct regulator_config cfg = {}; 435760423dfSChiYuan Huang int i, ret; 436760423dfSChiYuan Huang 437760423dfSChiYuan Huang priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); 438760423dfSChiYuan Huang if (!priv) 439760423dfSChiYuan Huang return -ENOMEM; 440760423dfSChiYuan Huang 441760423dfSChiYuan Huang priv->dev = &i2c->dev; 442760423dfSChiYuan Huang 443760423dfSChiYuan Huang priv->regmap = devm_regmap_init_i2c(i2c, &rt5190a_regmap_config); 444760423dfSChiYuan Huang if (IS_ERR(priv->regmap)) { 445760423dfSChiYuan Huang dev_err(&i2c->dev, "Failed to allocate regmap\n"); 446760423dfSChiYuan Huang return PTR_ERR(priv->regmap); 447760423dfSChiYuan Huang } 448760423dfSChiYuan Huang 449760423dfSChiYuan Huang ret = rt5190a_device_check(priv); 450760423dfSChiYuan Huang if (ret) { 451760423dfSChiYuan Huang dev_err(&i2c->dev, "Failed to check device %d\n", ret); 452760423dfSChiYuan Huang return ret; 453760423dfSChiYuan Huang } 454760423dfSChiYuan Huang 455760423dfSChiYuan Huang ret = rt5190a_device_initialize(priv); 456760423dfSChiYuan Huang if (ret) { 457760423dfSChiYuan Huang dev_err(&i2c->dev, "Failed to initialize the device\n"); 458760423dfSChiYuan Huang return ret; 459760423dfSChiYuan Huang } 460760423dfSChiYuan Huang 461760423dfSChiYuan Huang ret = rt5190a_parse_regulator_dt_data(priv); 462760423dfSChiYuan Huang if (ret) { 463760423dfSChiYuan Huang dev_err(&i2c->dev, "Failed to parse regulator dt\n"); 464760423dfSChiYuan Huang return ret; 465760423dfSChiYuan Huang } 466760423dfSChiYuan Huang 467760423dfSChiYuan Huang cfg.dev = &i2c->dev; 468760423dfSChiYuan Huang cfg.regmap = priv->regmap; 469760423dfSChiYuan Huang 470760423dfSChiYuan Huang for (i = 0; i < RT5190A_MAX_IDX; i++) { 471760423dfSChiYuan Huang struct regulator_desc *desc = priv->rdesc + i; 472760423dfSChiYuan Huang struct of_regulator_match *match = rt5190a_regulator_match + i; 473760423dfSChiYuan Huang 474760423dfSChiYuan Huang cfg.init_data = match->init_data; 475760423dfSChiYuan Huang cfg.of_node = match->of_node; 476760423dfSChiYuan Huang 477760423dfSChiYuan Huang priv->rdev[i] = devm_regulator_register(&i2c->dev, desc, &cfg); 478760423dfSChiYuan Huang if (IS_ERR(priv->rdev[i])) { 479760423dfSChiYuan Huang dev_err(&i2c->dev, "Failed to register regulator %s\n", 480760423dfSChiYuan Huang desc->name); 481760423dfSChiYuan Huang return PTR_ERR(priv->rdev[i]); 482760423dfSChiYuan Huang } 483760423dfSChiYuan Huang } 484760423dfSChiYuan Huang 485760423dfSChiYuan Huang if (i2c->irq) { 486760423dfSChiYuan Huang ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, 487760423dfSChiYuan Huang rt5190a_irq_handler, 488760423dfSChiYuan Huang IRQF_ONESHOT, 489760423dfSChiYuan Huang dev_name(&i2c->dev), priv); 490760423dfSChiYuan Huang if (ret) { 491760423dfSChiYuan Huang dev_err(&i2c->dev, "Failed to register interrupt\n"); 492760423dfSChiYuan Huang return ret; 493760423dfSChiYuan Huang } 494760423dfSChiYuan Huang } 495760423dfSChiYuan Huang 496760423dfSChiYuan Huang return 0; 497760423dfSChiYuan Huang } 498760423dfSChiYuan Huang 499760423dfSChiYuan Huang static const struct of_device_id __maybe_unused rt5190a_device_table[] = { 500760423dfSChiYuan Huang { .compatible = "richtek,rt5190a", }, 501760423dfSChiYuan Huang {} 502760423dfSChiYuan Huang }; 503760423dfSChiYuan Huang MODULE_DEVICE_TABLE(of, rt5190a_device_table); 504760423dfSChiYuan Huang 505760423dfSChiYuan Huang static struct i2c_driver rt5190a_driver = { 506760423dfSChiYuan Huang .driver = { 507760423dfSChiYuan Huang .name = "rt5190a", 508*41cff178SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS, 509760423dfSChiYuan Huang .of_match_table = rt5190a_device_table, 510760423dfSChiYuan Huang }, 511760423dfSChiYuan Huang .probe_new = rt5190a_probe, 512760423dfSChiYuan Huang }; 513760423dfSChiYuan Huang module_i2c_driver(rt5190a_driver); 514760423dfSChiYuan Huang 515760423dfSChiYuan Huang MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); 516760423dfSChiYuan Huang MODULE_DESCRIPTION("Richtek RT5190A Regulator Driver"); 517760423dfSChiYuan Huang MODULE_LICENSE("GPL v2"); 518