1a747070eSChiYuan Huang // SPDX-License-Identifier: GPL-2.0+ 2a747070eSChiYuan Huang 3a747070eSChiYuan Huang #include <linux/bitops.h> 4a747070eSChiYuan Huang #include <linux/delay.h> 5a747070eSChiYuan Huang #include <linux/gpio/consumer.h> 6a747070eSChiYuan Huang #include <linux/i2c.h> 7a747070eSChiYuan Huang #include <linux/kernel.h> 8a747070eSChiYuan Huang #include <linux/module.h> 9a747070eSChiYuan Huang #include <linux/regmap.h> 10a747070eSChiYuan Huang #include <linux/regulator/driver.h> 11a747070eSChiYuan Huang #include <linux/regulator/of_regulator.h> 12a747070eSChiYuan Huang 13a747070eSChiYuan Huang #define RT6245_VIRT_OCLIMIT 0x00 14a747070eSChiYuan Huang #define RT6245_VIRT_OTLEVEL 0x01 15a747070eSChiYuan Huang #define RT6245_VIRT_PGDLYTIME 0x02 16a747070eSChiYuan Huang #define RT6245_VIRT_SLEWRATE 0x03 17a747070eSChiYuan Huang #define RT6245_VIRT_SWFREQ 0x04 18a747070eSChiYuan Huang #define RT6245_VIRT_VOUT 0x05 19a747070eSChiYuan Huang 20a747070eSChiYuan Huang #define RT6245_VOUT_MASK GENMASK(6, 0) 21a747070eSChiYuan Huang #define RT6245_SLEW_MASK GENMASK(2, 0) 22a747070eSChiYuan Huang #define RT6245_CHKSUM_MASK BIT(7) 23a747070eSChiYuan Huang #define RT6245_CODE_MASK GENMASK(6, 0) 24a747070eSChiYuan Huang 25a747070eSChiYuan Huang /* HW Enable + Soft start time */ 26a747070eSChiYuan Huang #define RT6245_ENTIME_IN_US 5000 27a747070eSChiYuan Huang 28a747070eSChiYuan Huang #define RT6245_VOUT_MINUV 437500 29a747070eSChiYuan Huang #define RT6245_VOUT_MAXUV 1387500 30a747070eSChiYuan Huang #define RT6245_VOUT_STEPUV 12500 31a747070eSChiYuan Huang #define RT6245_NUM_VOUT ((RT6245_VOUT_MAXUV - RT6245_VOUT_MINUV) / RT6245_VOUT_STEPUV + 1) 32a747070eSChiYuan Huang 33a747070eSChiYuan Huang struct rt6245_priv { 34a747070eSChiYuan Huang struct gpio_desc *enable_gpio; 35a747070eSChiYuan Huang bool enable_state; 36a747070eSChiYuan Huang }; 37a747070eSChiYuan Huang 38a747070eSChiYuan Huang static int rt6245_enable(struct regulator_dev *rdev) 39a747070eSChiYuan Huang { 40a747070eSChiYuan Huang struct rt6245_priv *priv = rdev_get_drvdata(rdev); 41a747070eSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 42a747070eSChiYuan Huang int ret; 43a747070eSChiYuan Huang 44a747070eSChiYuan Huang if (!priv->enable_gpio) 45a747070eSChiYuan Huang return 0; 46a747070eSChiYuan Huang 47a747070eSChiYuan Huang gpiod_direction_output(priv->enable_gpio, 1); 48a747070eSChiYuan Huang usleep_range(RT6245_ENTIME_IN_US, RT6245_ENTIME_IN_US + 1000); 49a747070eSChiYuan Huang 50a747070eSChiYuan Huang regcache_cache_only(regmap, false); 51a747070eSChiYuan Huang ret = regcache_sync(regmap); 52a747070eSChiYuan Huang if (ret) 53a747070eSChiYuan Huang return ret; 54a747070eSChiYuan Huang 55a747070eSChiYuan Huang priv->enable_state = true; 56a747070eSChiYuan Huang return 0; 57a747070eSChiYuan Huang } 58a747070eSChiYuan Huang 59a747070eSChiYuan Huang static int rt6245_disable(struct regulator_dev *rdev) 60a747070eSChiYuan Huang { 61a747070eSChiYuan Huang struct rt6245_priv *priv = rdev_get_drvdata(rdev); 62a747070eSChiYuan Huang struct regmap *regmap = rdev_get_regmap(rdev); 63a747070eSChiYuan Huang 64a747070eSChiYuan Huang if (!priv->enable_gpio) 65a747070eSChiYuan Huang return -EINVAL; 66a747070eSChiYuan Huang 67a747070eSChiYuan Huang regcache_cache_only(regmap, true); 68a747070eSChiYuan Huang regcache_mark_dirty(regmap); 69a747070eSChiYuan Huang 70a747070eSChiYuan Huang gpiod_direction_output(priv->enable_gpio, 0); 71a747070eSChiYuan Huang 72a747070eSChiYuan Huang priv->enable_state = false; 73a747070eSChiYuan Huang return 0; 74a747070eSChiYuan Huang } 75a747070eSChiYuan Huang 76a747070eSChiYuan Huang static int rt6245_is_enabled(struct regulator_dev *rdev) 77a747070eSChiYuan Huang { 78a747070eSChiYuan Huang struct rt6245_priv *priv = rdev_get_drvdata(rdev); 79a747070eSChiYuan Huang 80a747070eSChiYuan Huang return priv->enable_state ? 1 : 0; 81a747070eSChiYuan Huang } 82a747070eSChiYuan Huang 83a747070eSChiYuan Huang static const struct regulator_ops rt6245_regulator_ops = { 84a747070eSChiYuan Huang .list_voltage = regulator_list_voltage_linear, 85a747070eSChiYuan Huang .set_voltage_sel = regulator_set_voltage_sel_regmap, 86a747070eSChiYuan Huang .get_voltage_sel = regulator_get_voltage_sel_regmap, 87a747070eSChiYuan Huang .set_ramp_delay = regulator_set_ramp_delay_regmap, 88a747070eSChiYuan Huang .enable = rt6245_enable, 89a747070eSChiYuan Huang .disable = rt6245_disable, 90a747070eSChiYuan Huang .is_enabled = rt6245_is_enabled, 91a747070eSChiYuan Huang }; 92a747070eSChiYuan Huang 93a747070eSChiYuan Huang /* ramp delay dividend is 12500 uV/uS, and divisor from 1 to 8 */ 94a747070eSChiYuan Huang static const unsigned int rt6245_ramp_delay_table[] = { 95a747070eSChiYuan Huang 12500, 6250, 4167, 3125, 2500, 2083, 1786, 1562 96a747070eSChiYuan Huang }; 97a747070eSChiYuan Huang 98a747070eSChiYuan Huang static const struct regulator_desc rt6245_regulator_desc = { 99a747070eSChiYuan Huang .name = "rt6245-regulator", 100a747070eSChiYuan Huang .ops = &rt6245_regulator_ops, 101a747070eSChiYuan Huang .type = REGULATOR_VOLTAGE, 102a747070eSChiYuan Huang .min_uV = RT6245_VOUT_MINUV, 103a747070eSChiYuan Huang .uV_step = RT6245_VOUT_STEPUV, 104a747070eSChiYuan Huang .n_voltages = RT6245_NUM_VOUT, 105a747070eSChiYuan Huang .ramp_delay_table = rt6245_ramp_delay_table, 106a747070eSChiYuan Huang .n_ramp_values = ARRAY_SIZE(rt6245_ramp_delay_table), 107a747070eSChiYuan Huang .owner = THIS_MODULE, 108a747070eSChiYuan Huang .vsel_reg = RT6245_VIRT_VOUT, 109a747070eSChiYuan Huang .vsel_mask = RT6245_VOUT_MASK, 110a747070eSChiYuan Huang .ramp_reg = RT6245_VIRT_SLEWRATE, 111a747070eSChiYuan Huang .ramp_mask = RT6245_SLEW_MASK, 112a747070eSChiYuan Huang }; 113a747070eSChiYuan Huang 114a747070eSChiYuan Huang static int rt6245_init_device_properties(struct device *dev) 115a747070eSChiYuan Huang { 116a747070eSChiYuan Huang const struct { 117a747070eSChiYuan Huang const char *name; 118a747070eSChiYuan Huang unsigned int reg; 119a747070eSChiYuan Huang } rt6245_props[] = { 120a747070eSChiYuan Huang { "richtek,oc-level-select", RT6245_VIRT_OCLIMIT }, 121a747070eSChiYuan Huang { "richtek,ot-level-select", RT6245_VIRT_OTLEVEL }, 122a747070eSChiYuan Huang { "richtek,pgdly-time-select", RT6245_VIRT_PGDLYTIME }, 123a747070eSChiYuan Huang { "richtek,switch-freq-select", RT6245_VIRT_SWFREQ } 124a747070eSChiYuan Huang }; 125a747070eSChiYuan Huang struct regmap *regmap = dev_get_regmap(dev, NULL); 126a747070eSChiYuan Huang u8 propval; 127a747070eSChiYuan Huang int i, ret; 128a747070eSChiYuan Huang 129a747070eSChiYuan Huang for (i = 0; i < ARRAY_SIZE(rt6245_props); i++) { 130a747070eSChiYuan Huang ret = device_property_read_u8(dev, rt6245_props[i].name, &propval); 131a747070eSChiYuan Huang if (ret) 132a747070eSChiYuan Huang continue; 133a747070eSChiYuan Huang 134a747070eSChiYuan Huang ret = regmap_write(regmap, rt6245_props[i].reg, propval); 135a747070eSChiYuan Huang if (ret) { 136a747070eSChiYuan Huang dev_err(dev, "Fail to apply [%s:%d]\n", rt6245_props[i].name, propval); 137a747070eSChiYuan Huang return ret; 138a747070eSChiYuan Huang } 139a747070eSChiYuan Huang } 140a747070eSChiYuan Huang 141a747070eSChiYuan Huang return 0; 142a747070eSChiYuan Huang } 143a747070eSChiYuan Huang 144a747070eSChiYuan Huang static int rt6245_reg_write(void *context, unsigned int reg, unsigned int val) 145a747070eSChiYuan Huang { 146a747070eSChiYuan Huang struct i2c_client *i2c = context; 147508f8ccdSColin Ian King static const u8 func_base[] = { 0x6F, 0x73, 0x78, 0x61, 0x7C, 0 }; 148a747070eSChiYuan Huang unsigned int code, bit_count; 149a747070eSChiYuan Huang 150a747070eSChiYuan Huang code = func_base[reg]; 151a747070eSChiYuan Huang code += val; 152a747070eSChiYuan Huang 153a747070eSChiYuan Huang /* xor checksum for bit 6 to 0 */ 154a747070eSChiYuan Huang bit_count = hweight8(code & RT6245_CODE_MASK); 155a747070eSChiYuan Huang if (bit_count % 2) 156a747070eSChiYuan Huang code |= RT6245_CHKSUM_MASK; 157a747070eSChiYuan Huang else 158a747070eSChiYuan Huang code &= ~RT6245_CHKSUM_MASK; 159a747070eSChiYuan Huang 160a747070eSChiYuan Huang return i2c_smbus_write_byte(i2c, code); 161a747070eSChiYuan Huang } 162a747070eSChiYuan Huang 163a747070eSChiYuan Huang static const struct reg_default rt6245_reg_defaults[] = { 164a747070eSChiYuan Huang /* Default over current 14A */ 165a747070eSChiYuan Huang { RT6245_VIRT_OCLIMIT, 2 }, 166a747070eSChiYuan Huang /* Default over temperature 150'c */ 167a747070eSChiYuan Huang { RT6245_VIRT_OTLEVEL, 0 }, 168a747070eSChiYuan Huang /* Default power good delay time 10us */ 169a747070eSChiYuan Huang { RT6245_VIRT_PGDLYTIME, 1 }, 170a747070eSChiYuan Huang /* Default slewrate 12.5mV/uS */ 171a747070eSChiYuan Huang { RT6245_VIRT_SLEWRATE, 0 }, 172a747070eSChiYuan Huang /* Default switch frequency 800KHz */ 173a747070eSChiYuan Huang { RT6245_VIRT_SWFREQ, 1 }, 174a747070eSChiYuan Huang /* Default voltage 750mV */ 175a747070eSChiYuan Huang { RT6245_VIRT_VOUT, 0x19 } 176a747070eSChiYuan Huang }; 177a747070eSChiYuan Huang 178a747070eSChiYuan Huang static const struct regmap_config rt6245_regmap_config = { 179a747070eSChiYuan Huang .reg_bits = 8, 180a747070eSChiYuan Huang .val_bits = 8, 181a747070eSChiYuan Huang .max_register = RT6245_VIRT_VOUT, 182a747070eSChiYuan Huang .cache_type = REGCACHE_FLAT, 183a747070eSChiYuan Huang .reg_defaults = rt6245_reg_defaults, 184a747070eSChiYuan Huang .num_reg_defaults = ARRAY_SIZE(rt6245_reg_defaults), 185a747070eSChiYuan Huang .reg_write = rt6245_reg_write, 186a747070eSChiYuan Huang }; 187a747070eSChiYuan Huang 188a747070eSChiYuan Huang static int rt6245_probe(struct i2c_client *i2c) 189a747070eSChiYuan Huang { 190a747070eSChiYuan Huang struct rt6245_priv *priv; 191a747070eSChiYuan Huang struct regmap *regmap; 192a747070eSChiYuan Huang struct regulator_config regulator_cfg = {}; 193a747070eSChiYuan Huang struct regulator_dev *rdev; 194a747070eSChiYuan Huang int ret; 195a747070eSChiYuan Huang 196a747070eSChiYuan Huang priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); 197a747070eSChiYuan Huang if (!priv) 198a747070eSChiYuan Huang return -ENOMEM; 199a747070eSChiYuan Huang 200a747070eSChiYuan Huang priv->enable_state = true; 201a747070eSChiYuan Huang 202a747070eSChiYuan Huang priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable", GPIOD_OUT_HIGH); 203a747070eSChiYuan Huang if (IS_ERR(priv->enable_gpio)) { 204a747070eSChiYuan Huang dev_err(&i2c->dev, "Failed to get 'enable' gpio\n"); 205a747070eSChiYuan Huang return PTR_ERR(priv->enable_gpio); 206a747070eSChiYuan Huang } 207a747070eSChiYuan Huang 208a747070eSChiYuan Huang usleep_range(RT6245_ENTIME_IN_US, RT6245_ENTIME_IN_US + 1000); 209a747070eSChiYuan Huang 210a747070eSChiYuan Huang regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt6245_regmap_config); 211a747070eSChiYuan Huang if (IS_ERR(regmap)) { 212a747070eSChiYuan Huang dev_err(&i2c->dev, "Failed to initialize the regmap\n"); 213a747070eSChiYuan Huang return PTR_ERR(regmap); 214a747070eSChiYuan Huang } 215a747070eSChiYuan Huang 216a747070eSChiYuan Huang ret = rt6245_init_device_properties(&i2c->dev); 217a747070eSChiYuan Huang if (ret) { 218a747070eSChiYuan Huang dev_err(&i2c->dev, "Failed to initialize device properties\n"); 219a747070eSChiYuan Huang return ret; 220a747070eSChiYuan Huang } 221a747070eSChiYuan Huang 222a747070eSChiYuan Huang regulator_cfg.dev = &i2c->dev; 223a747070eSChiYuan Huang regulator_cfg.of_node = i2c->dev.of_node; 224a747070eSChiYuan Huang regulator_cfg.regmap = regmap; 225a747070eSChiYuan Huang regulator_cfg.driver_data = priv; 226a747070eSChiYuan Huang regulator_cfg.init_data = of_get_regulator_init_data(&i2c->dev, i2c->dev.of_node, 227a747070eSChiYuan Huang &rt6245_regulator_desc); 228a747070eSChiYuan Huang rdev = devm_regulator_register(&i2c->dev, &rt6245_regulator_desc, ®ulator_cfg); 229a747070eSChiYuan Huang if (IS_ERR(rdev)) { 230a747070eSChiYuan Huang dev_err(&i2c->dev, "Failed to register regulator\n"); 231a747070eSChiYuan Huang return PTR_ERR(rdev); 232a747070eSChiYuan Huang } 233a747070eSChiYuan Huang 234a747070eSChiYuan Huang return 0; 235a747070eSChiYuan Huang } 236a747070eSChiYuan Huang 237a747070eSChiYuan Huang static const struct of_device_id __maybe_unused rt6245_of_match_table[] = { 238a747070eSChiYuan Huang { .compatible = "richtek,rt6245", }, 239a747070eSChiYuan Huang {} 240a747070eSChiYuan Huang }; 241a747070eSChiYuan Huang MODULE_DEVICE_TABLE(of, rt6245_of_match_table); 242a747070eSChiYuan Huang 243a747070eSChiYuan Huang static struct i2c_driver rt6245_driver = { 244a747070eSChiYuan Huang .driver = { 245a747070eSChiYuan Huang .name = "rt6245", 246*46600ab1SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS, 247a747070eSChiYuan Huang .of_match_table = rt6245_of_match_table, 248a747070eSChiYuan Huang }, 249a747070eSChiYuan Huang .probe_new = rt6245_probe, 250a747070eSChiYuan Huang }; 251a747070eSChiYuan Huang module_i2c_driver(rt6245_driver); 252a747070eSChiYuan Huang 253a747070eSChiYuan Huang MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); 254a747070eSChiYuan Huang MODULE_DESCRIPTION("Richtek RT6245 Regulator Driver"); 255a747070eSChiYuan Huang MODULE_LICENSE("GPL v2"); 256