1e6999e7cSChiYuan Huang // SPDX-License-Identifier: GPL-2.0-only 2e6999e7cSChiYuan Huang /* 3e6999e7cSChiYuan Huang * Copyright (C) 2022 Richtek Technology Corp. 4e6999e7cSChiYuan Huang * 5e6999e7cSChiYuan Huang * Author: ChiYuan Huang <cy_huang@richtek.com> 6e6999e7cSChiYuan Huang * 7e6999e7cSChiYuan Huang */ 8e6999e7cSChiYuan Huang 9e6999e7cSChiYuan Huang #include <linux/bits.h> 10e6999e7cSChiYuan Huang #include <linux/delay.h> 11e6999e7cSChiYuan Huang #include <linux/gpio/consumer.h> 12e6999e7cSChiYuan Huang #include <linux/i2c.h> 13e6999e7cSChiYuan Huang #include <linux/interrupt.h> 14e6999e7cSChiYuan Huang #include <linux/kernel.h> 15e6999e7cSChiYuan Huang #include <linux/mod_devicetable.h> 16e6999e7cSChiYuan Huang #include <linux/module.h> 17e6999e7cSChiYuan Huang #include <linux/pm_runtime.h> 18e6999e7cSChiYuan Huang #include <linux/regmap.h> 19e6999e7cSChiYuan Huang #include <linux/regulator/consumer.h> 20e6999e7cSChiYuan Huang #include <linux/regulator/driver.h> 21e6999e7cSChiYuan Huang #include <linux/regulator/of_regulator.h> 22e6999e7cSChiYuan Huang 23e6999e7cSChiYuan Huang #define RT6190_REG_VID 0x00 24e6999e7cSChiYuan Huang #define RT6190_REG_OUTV 0x01 25e6999e7cSChiYuan Huang #define RT6190_REG_OUTC 0x03 26e6999e7cSChiYuan Huang #define RT6190_REG_SET1 0x0D 27e6999e7cSChiYuan Huang #define RT6190_REG_SET2 0x0E 28e6999e7cSChiYuan Huang #define RT6190_REG_SET4 0x10 29e6999e7cSChiYuan Huang #define RT6190_REG_RATIO 0x11 30e6999e7cSChiYuan Huang #define RT6190_REG_OUT_VOLT_L 0x12 31e6999e7cSChiYuan Huang #define RT6190_REG_TEMP_H 0x1B 32e6999e7cSChiYuan Huang #define RT6190_REG_STAT1 0x1C 33e6999e7cSChiYuan Huang #define RT6190_REG_ALERT1 0x1E 34e6999e7cSChiYuan Huang #define RT6190_REG_ALERT2 0x1F 35e6999e7cSChiYuan Huang #define RT6190_REG_MASK2 0x21 36e6999e7cSChiYuan Huang #define RT6190_REG_OCPEN 0x28 37e6999e7cSChiYuan Huang #define RT6190_REG_SET5 0x29 38e6999e7cSChiYuan Huang #define RT6190_REG_VBUSC_ADC 0x32 39e6999e7cSChiYuan Huang #define RT6190_REG_BUSC_VOLT_L 0x33 40e6999e7cSChiYuan Huang #define RT6190_REG_BUSC_VOLT_H 0x34 41e6999e7cSChiYuan Huang #define RT6190_REG_STAT3 0x37 42e6999e7cSChiYuan Huang #define RT6190_REG_ALERT3 0x38 43e6999e7cSChiYuan Huang #define RT6190_REG_MASK3 0x39 44e6999e7cSChiYuan Huang 45e6999e7cSChiYuan Huang #define RT6190_ENPWM_MASK BIT(7) 46e6999e7cSChiYuan Huang #define RT6190_ENDCHG_MASK BIT(4) 47e6999e7cSChiYuan Huang #define RT6190_ALERT_OTPEVT BIT(6) 48e6999e7cSChiYuan Huang #define RT6190_ALERT_UVPEVT BIT(5) 49e6999e7cSChiYuan Huang #define RT6190_ALERT_OVPEVT BIT(4) 50e6999e7cSChiYuan Huang #define RT6190_ENGCP_MASK BIT(1) 51e6999e7cSChiYuan Huang #define RT6190_FCCM_MASK BIT(7) 52e6999e7cSChiYuan Huang 53e6999e7cSChiYuan Huang #define RICHTEK_VID 0x82 54e6999e7cSChiYuan Huang #define RT6190_OUT_MIN_UV 3000000 55e6999e7cSChiYuan Huang #define RT6190_OUT_MAX_UV 32000000 56e6999e7cSChiYuan Huang #define RT6190_OUT_STEP_UV 20000 57e6999e7cSChiYuan Huang #define RT6190_OUT_N_VOLT (RT6190_OUT_MAX_UV / RT6190_OUT_STEP_UV + 1) 58e6999e7cSChiYuan Huang #define RT6190_OUTV_MINSEL 150 59e6999e7cSChiYuan Huang #define RT6190_OUT_MIN_UA 306000 60e6999e7cSChiYuan Huang #define RT6190_OUT_MAX_UA 12114000 61e6999e7cSChiYuan Huang #define RT6190_OUT_STEP_UA 24000 62e6999e7cSChiYuan Huang #define RT6190_OUTC_MINSEL 19 63e6999e7cSChiYuan Huang #define RT6190_EN_TIME_US 500 64e6999e7cSChiYuan Huang 65e6999e7cSChiYuan Huang #define RT6190_PSM_MODE 0 66e6999e7cSChiYuan Huang #define RT6190_FCCM_MODE 1 67e6999e7cSChiYuan Huang 68e6999e7cSChiYuan Huang struct rt6190_data { 69e6999e7cSChiYuan Huang struct device *dev; 70e6999e7cSChiYuan Huang struct regmap *regmap; 71e6999e7cSChiYuan Huang struct gpio_desc *enable_gpio; 72e6999e7cSChiYuan Huang unsigned int cached_alert_evt; 73e6999e7cSChiYuan Huang }; 74e6999e7cSChiYuan Huang 75e6999e7cSChiYuan Huang static int rt6190_out_set_voltage_sel(struct regulator_dev *rdev, 76e6999e7cSChiYuan Huang unsigned int selector) 77e6999e7cSChiYuan Huang { 78e6999e7cSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 79e6999e7cSChiYuan Huang __le16 le_sel = cpu_to_le16(selector); 80e6999e7cSChiYuan Huang 81e6999e7cSChiYuan Huang return regmap_raw_write(regmap, RT6190_REG_OUTV, &le_sel, 82e6999e7cSChiYuan Huang sizeof(le_sel)); 83e6999e7cSChiYuan Huang } 84e6999e7cSChiYuan Huang 85e6999e7cSChiYuan Huang static int rt6190_out_get_voltage_sel(struct regulator_dev *rdev) 86e6999e7cSChiYuan Huang { 87e6999e7cSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 88e6999e7cSChiYuan Huang __le16 le_sel; 89e6999e7cSChiYuan Huang int ret; 90e6999e7cSChiYuan Huang 91e6999e7cSChiYuan Huang ret = regmap_raw_read(regmap, RT6190_REG_OUTV, &le_sel, sizeof(le_sel)); 92e6999e7cSChiYuan Huang 93e6999e7cSChiYuan Huang return ret ?: le16_to_cpu(le_sel); 94e6999e7cSChiYuan Huang } 95e6999e7cSChiYuan Huang 96e6999e7cSChiYuan Huang static int rt6190_out_enable(struct regulator_dev *rdev) 97e6999e7cSChiYuan Huang { 98e6999e7cSChiYuan Huang struct rt6190_data *data = rdev_get_drvdata(rdev); 99e6999e7cSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 100e6999e7cSChiYuan Huang u8 out_cfg[4]; 101e6999e7cSChiYuan Huang int ret; 102e6999e7cSChiYuan Huang 103e6999e7cSChiYuan Huang pm_runtime_get_sync(data->dev); 104e6999e7cSChiYuan Huang 105e6999e7cSChiYuan Huang /* 106e6999e7cSChiYuan Huang * From off to on, vout config will restore to IC default. 107e6999e7cSChiYuan Huang * Read vout configs before enable, and restore them after enable 108e6999e7cSChiYuan Huang */ 109e6999e7cSChiYuan Huang ret = regmap_raw_read(regmap, RT6190_REG_OUTV, out_cfg, 110e6999e7cSChiYuan Huang sizeof(out_cfg)); 111e6999e7cSChiYuan Huang if (ret) 112e6999e7cSChiYuan Huang return ret; 113e6999e7cSChiYuan Huang 114e6999e7cSChiYuan Huang ret = regulator_enable_regmap(rdev); 115e6999e7cSChiYuan Huang if (ret) 116e6999e7cSChiYuan Huang return ret; 117e6999e7cSChiYuan Huang 118e6999e7cSChiYuan Huang ret = regmap_raw_write(regmap, RT6190_REG_OUTV, out_cfg, 119e6999e7cSChiYuan Huang sizeof(out_cfg)); 120e6999e7cSChiYuan Huang if (ret) 121e6999e7cSChiYuan Huang return ret; 122e6999e7cSChiYuan Huang 123e6999e7cSChiYuan Huang return regmap_update_bits(regmap, RT6190_REG_SET5, RT6190_ENGCP_MASK, 124e6999e7cSChiYuan Huang RT6190_ENGCP_MASK); 125e6999e7cSChiYuan Huang } 126e6999e7cSChiYuan Huang 127e6999e7cSChiYuan Huang static int rt6190_out_disable(struct regulator_dev *rdev) 128e6999e7cSChiYuan Huang { 129e6999e7cSChiYuan Huang struct rt6190_data *data = rdev_get_drvdata(rdev); 130e6999e7cSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 131e6999e7cSChiYuan Huang int ret; 132e6999e7cSChiYuan Huang 133e6999e7cSChiYuan Huang ret = regmap_update_bits(regmap, RT6190_REG_SET5, RT6190_ENGCP_MASK, 0); 134e6999e7cSChiYuan Huang if (ret) 135e6999e7cSChiYuan Huang return ret; 136e6999e7cSChiYuan Huang 137e6999e7cSChiYuan Huang ret = regulator_disable_regmap(rdev); 138e6999e7cSChiYuan Huang if (ret) 139e6999e7cSChiYuan Huang return ret; 140e6999e7cSChiYuan Huang 141e6999e7cSChiYuan Huang /* cleared cached alert event */ 142e6999e7cSChiYuan Huang data->cached_alert_evt = 0; 143e6999e7cSChiYuan Huang 144e6999e7cSChiYuan Huang pm_runtime_put(data->dev); 145e6999e7cSChiYuan Huang 146e6999e7cSChiYuan Huang return 0; 147e6999e7cSChiYuan Huang } 148e6999e7cSChiYuan Huang 149e6999e7cSChiYuan Huang static int rt6190_out_set_current_limit(struct regulator_dev *rdev, int min_uA, 150e6999e7cSChiYuan Huang int max_uA) 151e6999e7cSChiYuan Huang { 152e6999e7cSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 153e6999e7cSChiYuan Huang int csel, clim; 154e6999e7cSChiYuan Huang __le16 le_csel; 155e6999e7cSChiYuan Huang 156e6999e7cSChiYuan Huang if (min_uA < RT6190_OUT_MIN_UA || max_uA > RT6190_OUT_MAX_UA) 157e6999e7cSChiYuan Huang return -EINVAL; 158e6999e7cSChiYuan Huang 159e6999e7cSChiYuan Huang csel = DIV_ROUND_UP(min_uA - RT6190_OUT_MIN_UA, RT6190_OUT_STEP_UA); 160e6999e7cSChiYuan Huang 161e6999e7cSChiYuan Huang clim = RT6190_OUT_MIN_UA + RT6190_OUT_STEP_UA * csel; 162e6999e7cSChiYuan Huang if (clim > max_uA) 163e6999e7cSChiYuan Huang return -EINVAL; 164e6999e7cSChiYuan Huang 165e6999e7cSChiYuan Huang csel += RT6190_OUTC_MINSEL; 166e6999e7cSChiYuan Huang le_csel = cpu_to_le16(csel); 167e6999e7cSChiYuan Huang 168e6999e7cSChiYuan Huang return regmap_raw_write(regmap, RT6190_REG_OUTC, &le_csel, 169e6999e7cSChiYuan Huang sizeof(le_csel)); 170e6999e7cSChiYuan Huang } 171e6999e7cSChiYuan Huang 172e6999e7cSChiYuan Huang static int rt6190_out_get_current_limit(struct regulator_dev *rdev) 173e6999e7cSChiYuan Huang { 174e6999e7cSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 175e6999e7cSChiYuan Huang __le16 le_csel; 176e6999e7cSChiYuan Huang int csel, ret; 177e6999e7cSChiYuan Huang 178e6999e7cSChiYuan Huang ret = regmap_raw_read(regmap, RT6190_REG_OUTC, &le_csel, 179e6999e7cSChiYuan Huang sizeof(le_csel)); 180e6999e7cSChiYuan Huang if (ret) 181e6999e7cSChiYuan Huang return ret; 182e6999e7cSChiYuan Huang 183e6999e7cSChiYuan Huang csel = le16_to_cpu(le_csel); 184e6999e7cSChiYuan Huang csel -= RT6190_OUTC_MINSEL; 185e6999e7cSChiYuan Huang 186e6999e7cSChiYuan Huang return RT6190_OUT_MIN_UA + RT6190_OUT_STEP_UA * csel; 187e6999e7cSChiYuan Huang } 188e6999e7cSChiYuan Huang 189e6999e7cSChiYuan Huang static int rt6190_out_set_mode(struct regulator_dev *rdev, unsigned int mode) 190e6999e7cSChiYuan Huang { 191e6999e7cSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 192e6999e7cSChiYuan Huang unsigned int val; 193e6999e7cSChiYuan Huang 194e6999e7cSChiYuan Huang switch (mode) { 195e6999e7cSChiYuan Huang case REGULATOR_MODE_FAST: 196e6999e7cSChiYuan Huang val = RT6190_FCCM_MASK; 197e6999e7cSChiYuan Huang break; 198e6999e7cSChiYuan Huang case REGULATOR_MODE_NORMAL: 199e6999e7cSChiYuan Huang val = 0; 200e6999e7cSChiYuan Huang break; 201e6999e7cSChiYuan Huang default: 202e6999e7cSChiYuan Huang return -EINVAL; 203e6999e7cSChiYuan Huang } 204e6999e7cSChiYuan Huang 205e6999e7cSChiYuan Huang return regmap_update_bits(regmap, RT6190_REG_SET1, RT6190_FCCM_MASK, 206e6999e7cSChiYuan Huang val); 207e6999e7cSChiYuan Huang } 208e6999e7cSChiYuan Huang 209e6999e7cSChiYuan Huang static unsigned int rt6190_out_get_mode(struct regulator_dev *rdev) 210e6999e7cSChiYuan Huang { 211e6999e7cSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 212e6999e7cSChiYuan Huang unsigned int config; 213e6999e7cSChiYuan Huang int ret; 214e6999e7cSChiYuan Huang 215e6999e7cSChiYuan Huang ret = regmap_read(regmap, RT6190_REG_SET1, &config); 216e6999e7cSChiYuan Huang if (ret) 217e6999e7cSChiYuan Huang return REGULATOR_MODE_INVALID; 218e6999e7cSChiYuan Huang 219e6999e7cSChiYuan Huang if (config & RT6190_FCCM_MASK) 220e6999e7cSChiYuan Huang return REGULATOR_MODE_FAST; 221e6999e7cSChiYuan Huang 222e6999e7cSChiYuan Huang return REGULATOR_MODE_NORMAL; 223e6999e7cSChiYuan Huang } 224e6999e7cSChiYuan Huang 225e6999e7cSChiYuan Huang static int rt6190_out_get_error_flags(struct regulator_dev *rdev, 226e6999e7cSChiYuan Huang unsigned int *flags) 227e6999e7cSChiYuan Huang { 228e6999e7cSChiYuan Huang struct rt6190_data *data = rdev_get_drvdata(rdev); 229e6999e7cSChiYuan Huang unsigned int state, rpt_flags = 0; 230e6999e7cSChiYuan Huang int ret; 231e6999e7cSChiYuan Huang 232e6999e7cSChiYuan Huang ret = regmap_read(data->regmap, RT6190_REG_STAT1, &state); 233e6999e7cSChiYuan Huang if (ret) 234e6999e7cSChiYuan Huang return ret; 235e6999e7cSChiYuan Huang 236e6999e7cSChiYuan Huang state |= data->cached_alert_evt; 237e6999e7cSChiYuan Huang 238e6999e7cSChiYuan Huang if (state & RT6190_ALERT_OTPEVT) 239e6999e7cSChiYuan Huang rpt_flags |= REGULATOR_ERROR_OVER_TEMP; 240e6999e7cSChiYuan Huang 241e6999e7cSChiYuan Huang if (state & RT6190_ALERT_UVPEVT) 242e6999e7cSChiYuan Huang rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE; 243e6999e7cSChiYuan Huang 244e6999e7cSChiYuan Huang if (state & RT6190_ALERT_OVPEVT) 245e6999e7cSChiYuan Huang rpt_flags |= REGULATOR_ERROR_REGULATION_OUT; 246e6999e7cSChiYuan Huang 247e6999e7cSChiYuan Huang *flags = rpt_flags; 248e6999e7cSChiYuan Huang 249e6999e7cSChiYuan Huang return 0; 250e6999e7cSChiYuan Huang } 251e6999e7cSChiYuan Huang 252e6999e7cSChiYuan Huang static unsigned int rt6190_out_of_map_mode(unsigned int mode) 253e6999e7cSChiYuan Huang { 254e6999e7cSChiYuan Huang switch (mode) { 255e6999e7cSChiYuan Huang case RT6190_PSM_MODE: 256e6999e7cSChiYuan Huang return REGULATOR_MODE_NORMAL; 257e6999e7cSChiYuan Huang case RT6190_FCCM_MODE: 258e6999e7cSChiYuan Huang return REGULATOR_MODE_FAST; 259e6999e7cSChiYuan Huang default: 260e6999e7cSChiYuan Huang return REGULATOR_MODE_INVALID; 261e6999e7cSChiYuan Huang } 262e6999e7cSChiYuan Huang } 263e6999e7cSChiYuan Huang 264e6999e7cSChiYuan Huang static const struct regulator_ops rt6190_regulator_ops = { 265e6999e7cSChiYuan Huang .list_voltage = regulator_list_voltage_linear, 266e6999e7cSChiYuan Huang .set_voltage_sel = rt6190_out_set_voltage_sel, 267e6999e7cSChiYuan Huang .get_voltage_sel = rt6190_out_get_voltage_sel, 268e6999e7cSChiYuan Huang .enable = rt6190_out_enable, 269e6999e7cSChiYuan Huang .disable = rt6190_out_disable, 270e6999e7cSChiYuan Huang .is_enabled = regulator_is_enabled_regmap, 271e6999e7cSChiYuan Huang .set_current_limit = rt6190_out_set_current_limit, 272e6999e7cSChiYuan Huang .get_current_limit = rt6190_out_get_current_limit, 273e6999e7cSChiYuan Huang .set_active_discharge = regulator_set_active_discharge_regmap, 274e6999e7cSChiYuan Huang .set_mode = rt6190_out_set_mode, 275e6999e7cSChiYuan Huang .get_mode = rt6190_out_get_mode, 276e6999e7cSChiYuan Huang .get_error_flags = rt6190_out_get_error_flags, 277e6999e7cSChiYuan Huang }; 278e6999e7cSChiYuan Huang 279e6999e7cSChiYuan Huang static const struct regulator_desc rt6190_regulator_desc = { 280e6999e7cSChiYuan Huang .name = "rt6190-regulator", 281e6999e7cSChiYuan Huang .type = REGULATOR_VOLTAGE, 282e6999e7cSChiYuan Huang .owner = THIS_MODULE, 283e6999e7cSChiYuan Huang .ops = &rt6190_regulator_ops, 284e6999e7cSChiYuan Huang .min_uV = RT6190_OUT_MIN_UV, 285e6999e7cSChiYuan Huang .uV_step = RT6190_OUT_STEP_UV, 286e6999e7cSChiYuan Huang .n_voltages = RT6190_OUT_N_VOLT, 287e6999e7cSChiYuan Huang .linear_min_sel = RT6190_OUTV_MINSEL, 288e6999e7cSChiYuan Huang .enable_reg = RT6190_REG_SET2, 289e6999e7cSChiYuan Huang .enable_mask = RT6190_ENPWM_MASK, 290e6999e7cSChiYuan Huang .active_discharge_reg = RT6190_REG_SET2, 291e6999e7cSChiYuan Huang .active_discharge_mask = RT6190_ENDCHG_MASK, 292e6999e7cSChiYuan Huang .active_discharge_on = RT6190_ENDCHG_MASK, 293e6999e7cSChiYuan Huang .of_map_mode = rt6190_out_of_map_mode, 294e6999e7cSChiYuan Huang }; 295e6999e7cSChiYuan Huang 296e6999e7cSChiYuan Huang static bool rt6190_is_volatile_reg(struct device *dev, unsigned int reg) 297e6999e7cSChiYuan Huang { 298e6999e7cSChiYuan Huang switch (reg) { 299e6999e7cSChiYuan Huang case RT6190_REG_OUT_VOLT_L ... RT6190_REG_ALERT2: 300e6999e7cSChiYuan Huang case RT6190_REG_BUSC_VOLT_L ... RT6190_REG_BUSC_VOLT_H: 301e6999e7cSChiYuan Huang case RT6190_REG_STAT3 ... RT6190_REG_ALERT3: 302e6999e7cSChiYuan Huang return true; 303e6999e7cSChiYuan Huang default: 304e6999e7cSChiYuan Huang return false; 305e6999e7cSChiYuan Huang } 306e6999e7cSChiYuan Huang } 307e6999e7cSChiYuan Huang 308e6999e7cSChiYuan Huang static const struct regmap_config rt6190_regmap_config = { 309e6999e7cSChiYuan Huang .name = "rt6190", 310e6999e7cSChiYuan Huang .cache_type = REGCACHE_FLAT, 311e6999e7cSChiYuan Huang .reg_bits = 8, 312e6999e7cSChiYuan Huang .val_bits = 8, 313e6999e7cSChiYuan Huang .max_register = RT6190_REG_MASK3, 314e6999e7cSChiYuan Huang .num_reg_defaults_raw = RT6190_REG_MASK3 + 1, 315e6999e7cSChiYuan Huang .volatile_reg = rt6190_is_volatile_reg, 316e6999e7cSChiYuan Huang }; 317e6999e7cSChiYuan Huang 318e6999e7cSChiYuan Huang static irqreturn_t rt6190_irq_handler(int irq, void *devid) 319e6999e7cSChiYuan Huang { 320e6999e7cSChiYuan Huang struct regulator_dev *rdev = devid; 321e6999e7cSChiYuan Huang struct rt6190_data *data = rdev_get_drvdata(rdev); 322e6999e7cSChiYuan Huang unsigned int alert; 323e6999e7cSChiYuan Huang int ret; 324e6999e7cSChiYuan Huang 325e6999e7cSChiYuan Huang ret = regmap_read(data->regmap, RT6190_REG_ALERT1, &alert); 326e6999e7cSChiYuan Huang if (ret) 327e6999e7cSChiYuan Huang return IRQ_NONE; 328e6999e7cSChiYuan Huang 329e6999e7cSChiYuan Huang /* Write clear alert events */ 330e6999e7cSChiYuan Huang ret = regmap_write(data->regmap, RT6190_REG_ALERT1, alert); 331e6999e7cSChiYuan Huang if (ret) 332e6999e7cSChiYuan Huang return IRQ_NONE; 333e6999e7cSChiYuan Huang 334e6999e7cSChiYuan Huang data->cached_alert_evt |= alert; 335e6999e7cSChiYuan Huang 336e6999e7cSChiYuan Huang if (alert & RT6190_ALERT_OTPEVT) 337e6999e7cSChiYuan Huang regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_TEMP, NULL); 338e6999e7cSChiYuan Huang 339e6999e7cSChiYuan Huang if (alert & RT6190_ALERT_UVPEVT) 340e6999e7cSChiYuan Huang regulator_notifier_call_chain(rdev, REGULATOR_EVENT_UNDER_VOLTAGE, NULL); 341e6999e7cSChiYuan Huang 342e6999e7cSChiYuan Huang if (alert & RT6190_ALERT_OVPEVT) 343e6999e7cSChiYuan Huang regulator_notifier_call_chain(rdev, REGULATOR_EVENT_REGULATION_OUT, NULL); 344e6999e7cSChiYuan Huang 345e6999e7cSChiYuan Huang return IRQ_HANDLED; 346e6999e7cSChiYuan Huang } 347e6999e7cSChiYuan Huang 348e6999e7cSChiYuan Huang static int rt6190_init_registers(struct regmap *regmap) 349e6999e7cSChiYuan Huang { 350e6999e7cSChiYuan Huang int ret; 351e6999e7cSChiYuan Huang 352e6999e7cSChiYuan Huang /* Enable_ADC = 1 */ 353e6999e7cSChiYuan Huang ret = regmap_write(regmap, RT6190_REG_SET4, 0x82); 354e6999e7cSChiYuan Huang if (ret) 355e6999e7cSChiYuan Huang return ret; 356e6999e7cSChiYuan Huang 357e6999e7cSChiYuan Huang /* Config default VOUT ratio to be higher */ 358e6999e7cSChiYuan Huang ret = regmap_write(regmap, RT6190_REG_RATIO, 0x20); 359e6999e7cSChiYuan Huang 360e6999e7cSChiYuan Huang /* Mask unused alert */ 361e6999e7cSChiYuan Huang ret = regmap_write(regmap, RT6190_REG_MASK2, 0); 362e6999e7cSChiYuan Huang if (ret) 363e6999e7cSChiYuan Huang return ret; 364e6999e7cSChiYuan Huang 365e6999e7cSChiYuan Huang /* OCP config */ 366e6999e7cSChiYuan Huang ret = regmap_write(regmap, RT6190_REG_OCPEN, 0); 367e6999e7cSChiYuan Huang if (ret) 368e6999e7cSChiYuan Huang return ret; 369e6999e7cSChiYuan Huang 370e6999e7cSChiYuan Huang /* Enable VBUSC ADC */ 371e6999e7cSChiYuan Huang return regmap_write(regmap, RT6190_REG_VBUSC_ADC, 0x02); 372e6999e7cSChiYuan Huang } 373e6999e7cSChiYuan Huang 374e6999e7cSChiYuan Huang static int rt6190_probe(struct i2c_client *i2c) 375e6999e7cSChiYuan Huang { 376e6999e7cSChiYuan Huang struct device *dev = &i2c->dev; 377e6999e7cSChiYuan Huang struct rt6190_data *data; 378e6999e7cSChiYuan Huang struct gpio_desc *enable_gpio; 379e6999e7cSChiYuan Huang struct regmap *regmap; 380e6999e7cSChiYuan Huang struct regulator_dev *rdev; 381e6999e7cSChiYuan Huang struct regulator_config cfg = {}; 382e6999e7cSChiYuan Huang unsigned int vid; 383e6999e7cSChiYuan Huang int ret; 384e6999e7cSChiYuan Huang 385e6999e7cSChiYuan Huang data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 386e6999e7cSChiYuan Huang if (!data) 387e6999e7cSChiYuan Huang return -ENOMEM; 388e6999e7cSChiYuan Huang 389e6999e7cSChiYuan Huang enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); 390e6999e7cSChiYuan Huang if (IS_ERR(enable_gpio)) 391e6999e7cSChiYuan Huang return dev_err_probe(dev, PTR_ERR(enable_gpio), "Failed to get 'enable' gpio\n"); 392e6999e7cSChiYuan Huang else if (enable_gpio) 393e6999e7cSChiYuan Huang usleep_range(RT6190_EN_TIME_US, RT6190_EN_TIME_US * 2); 394e6999e7cSChiYuan Huang 395e6999e7cSChiYuan Huang regmap = devm_regmap_init_i2c(i2c, &rt6190_regmap_config); 396e6999e7cSChiYuan Huang if (IS_ERR(regmap)) 397e6999e7cSChiYuan Huang return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n"); 398e6999e7cSChiYuan Huang 399e6999e7cSChiYuan Huang data->dev = dev; 400e6999e7cSChiYuan Huang data->enable_gpio = enable_gpio; 401e6999e7cSChiYuan Huang data->regmap = regmap; 402e6999e7cSChiYuan Huang i2c_set_clientdata(i2c, data); 403e6999e7cSChiYuan Huang 404e6999e7cSChiYuan Huang ret = regmap_read(regmap, RT6190_REG_VID, &vid); 405e6999e7cSChiYuan Huang if (ret) 406e6999e7cSChiYuan Huang return dev_err_probe(dev, ret, "Failed to read VID\n"); 407e6999e7cSChiYuan Huang 408e6999e7cSChiYuan Huang if (vid != RICHTEK_VID) 409e6999e7cSChiYuan Huang return dev_err_probe(dev, -ENODEV, "Incorrect VID 0x%02x\n", vid); 410e6999e7cSChiYuan Huang 411e6999e7cSChiYuan Huang ret = rt6190_init_registers(regmap); 412e6999e7cSChiYuan Huang if (ret) 413e6999e7cSChiYuan Huang return dev_err_probe(dev, ret, "Failed to init registers\n"); 414e6999e7cSChiYuan Huang 415e6999e7cSChiYuan Huang pm_runtime_set_active(dev); 416e6999e7cSChiYuan Huang ret = devm_pm_runtime_enable(dev); 417e6999e7cSChiYuan Huang if (ret) 418e6999e7cSChiYuan Huang return dev_err_probe(dev, ret, "Failed to set pm_runtime enable\n"); 419e6999e7cSChiYuan Huang 420e6999e7cSChiYuan Huang cfg.dev = dev; 421e6999e7cSChiYuan Huang cfg.of_node = dev->of_node; 422e6999e7cSChiYuan Huang cfg.driver_data = data; 423e6999e7cSChiYuan Huang cfg.init_data = of_get_regulator_init_data(dev, dev->of_node, 424e6999e7cSChiYuan Huang &rt6190_regulator_desc); 425e6999e7cSChiYuan Huang 426e6999e7cSChiYuan Huang rdev = devm_regulator_register(dev, &rt6190_regulator_desc, &cfg); 427e6999e7cSChiYuan Huang if (IS_ERR(rdev)) 428e6999e7cSChiYuan Huang return dev_err_probe(dev, PTR_ERR(rdev), "Failed to register regulator\n"); 429e6999e7cSChiYuan Huang 430e6999e7cSChiYuan Huang if (i2c->irq) { 431e6999e7cSChiYuan Huang ret = devm_request_threaded_irq(dev, i2c->irq, NULL, 432e6999e7cSChiYuan Huang rt6190_irq_handler, 433e6999e7cSChiYuan Huang IRQF_ONESHOT, dev_name(dev), 434e6999e7cSChiYuan Huang rdev); 435e6999e7cSChiYuan Huang if (ret) 436e6999e7cSChiYuan Huang return dev_err_probe(dev, ret, "Failed to register interrupt\n"); 437e6999e7cSChiYuan Huang } 438e6999e7cSChiYuan Huang 439e6999e7cSChiYuan Huang return 0; 440e6999e7cSChiYuan Huang } 441e6999e7cSChiYuan Huang 442e6999e7cSChiYuan Huang static int rt6190_runtime_suspend(struct device *dev) 443e6999e7cSChiYuan Huang { 444e6999e7cSChiYuan Huang struct rt6190_data *data = dev_get_drvdata(dev); 445e6999e7cSChiYuan Huang struct regmap *regmap = data->regmap; 446e6999e7cSChiYuan Huang 447e6999e7cSChiYuan Huang if (!data->enable_gpio) 448e6999e7cSChiYuan Huang return 0; 449e6999e7cSChiYuan Huang 450e6999e7cSChiYuan Huang regcache_cache_only(regmap, true); 451e6999e7cSChiYuan Huang regcache_mark_dirty(regmap); 452e6999e7cSChiYuan Huang 453e6999e7cSChiYuan Huang gpiod_set_value(data->enable_gpio, 0); 454e6999e7cSChiYuan Huang 455e6999e7cSChiYuan Huang return 0; 456e6999e7cSChiYuan Huang } 457e6999e7cSChiYuan Huang 458e6999e7cSChiYuan Huang static int rt6190_runtime_resume(struct device *dev) 459e6999e7cSChiYuan Huang { 460e6999e7cSChiYuan Huang struct rt6190_data *data = dev_get_drvdata(dev); 461e6999e7cSChiYuan Huang struct regmap *regmap = data->regmap; 462e6999e7cSChiYuan Huang 463e6999e7cSChiYuan Huang if (!data->enable_gpio) 464e6999e7cSChiYuan Huang return 0; 465e6999e7cSChiYuan Huang 466e6999e7cSChiYuan Huang gpiod_set_value(data->enable_gpio, 1); 467e6999e7cSChiYuan Huang usleep_range(RT6190_EN_TIME_US, RT6190_EN_TIME_US * 2); 468e6999e7cSChiYuan Huang 469e6999e7cSChiYuan Huang regcache_cache_only(regmap, false); 470e6999e7cSChiYuan Huang return regcache_sync(regmap); 471e6999e7cSChiYuan Huang } 472e6999e7cSChiYuan Huang 473e6999e7cSChiYuan Huang static const struct dev_pm_ops __maybe_unused rt6190_dev_pm = { 474e6999e7cSChiYuan Huang RUNTIME_PM_OPS(rt6190_runtime_suspend, rt6190_runtime_resume, NULL) 475e6999e7cSChiYuan Huang }; 476e6999e7cSChiYuan Huang 477e6999e7cSChiYuan Huang static const struct of_device_id rt6190_of_dev_table[] = { 478e6999e7cSChiYuan Huang { .compatible = "richtek,rt6190" }, 479e6999e7cSChiYuan Huang {} 480e6999e7cSChiYuan Huang }; 481e6999e7cSChiYuan Huang MODULE_DEVICE_TABLE(of, rt6190_of_dev_table); 482e6999e7cSChiYuan Huang 483e6999e7cSChiYuan Huang static struct i2c_driver rt6190_driver = { 484e6999e7cSChiYuan Huang .driver = { 485e6999e7cSChiYuan Huang .name = "rt6190", 486*bdce47bbSDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS, 487e6999e7cSChiYuan Huang .of_match_table = rt6190_of_dev_table, 488e6999e7cSChiYuan Huang .pm = pm_ptr(&rt6190_dev_pm), 489e6999e7cSChiYuan Huang }, 490e6999e7cSChiYuan Huang .probe_new = rt6190_probe, 491e6999e7cSChiYuan Huang }; 492e6999e7cSChiYuan Huang module_i2c_driver(rt6190_driver); 493e6999e7cSChiYuan Huang 494e6999e7cSChiYuan Huang MODULE_DESCRIPTION("Richtek RT6190 regulator driver"); 495e6999e7cSChiYuan Huang MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); 496e6999e7cSChiYuan Huang MODULE_LICENSE("GPL"); 497