162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// da9211-regulator.c - Regulator device driver for DA9211/DA9212 462306a36Sopenharmony_ci// /DA9213/DA9223/DA9214/DA9224/DA9215/DA9225 562306a36Sopenharmony_ci// Copyright (C) 2015 Dialog Semiconductor Ltd. 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/err.h> 862306a36Sopenharmony_ci#include <linux/i2c.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1362306a36Sopenharmony_ci#include <linux/regulator/machine.h> 1462306a36Sopenharmony_ci#include <linux/regmap.h> 1562306a36Sopenharmony_ci#include <linux/irq.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1862306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 1962306a36Sopenharmony_ci#include <linux/regulator/da9211.h> 2062306a36Sopenharmony_ci#include <dt-bindings/regulator/dlg,da9211-regulator.h> 2162306a36Sopenharmony_ci#include "da9211-regulator.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* DEVICE IDs */ 2462306a36Sopenharmony_ci#define DA9211_DEVICE_ID 0x22 2562306a36Sopenharmony_ci#define DA9213_DEVICE_ID 0x23 2662306a36Sopenharmony_ci#define DA9215_DEVICE_ID 0x24 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* DA9211 REGULATOR IDs */ 2962306a36Sopenharmony_ci#define DA9211_ID_BUCKA 0 3062306a36Sopenharmony_ci#define DA9211_ID_BUCKB 1 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistruct da9211 { 3362306a36Sopenharmony_ci struct device *dev; 3462306a36Sopenharmony_ci struct regmap *regmap; 3562306a36Sopenharmony_ci struct da9211_pdata *pdata; 3662306a36Sopenharmony_ci struct regulator_dev *rdev[DA9211_MAX_REGULATORS]; 3762306a36Sopenharmony_ci int num_regulator; 3862306a36Sopenharmony_ci int chip_irq; 3962306a36Sopenharmony_ci int chip_id; 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic const struct regmap_range_cfg da9211_regmap_range[] = { 4362306a36Sopenharmony_ci { 4462306a36Sopenharmony_ci .selector_reg = DA9211_REG_PAGE_CON, 4562306a36Sopenharmony_ci .selector_mask = DA9211_REG_PAGE_MASK, 4662306a36Sopenharmony_ci .selector_shift = DA9211_REG_PAGE_SHIFT, 4762306a36Sopenharmony_ci .window_start = 0, 4862306a36Sopenharmony_ci .window_len = 256, 4962306a36Sopenharmony_ci .range_min = 0, 5062306a36Sopenharmony_ci .range_max = 5*128, 5162306a36Sopenharmony_ci }, 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic bool da9211_volatile_reg(struct device *dev, unsigned int reg) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci switch (reg) { 5762306a36Sopenharmony_ci case DA9211_REG_STATUS_A: 5862306a36Sopenharmony_ci case DA9211_REG_STATUS_B: 5962306a36Sopenharmony_ci case DA9211_REG_EVENT_A: 6062306a36Sopenharmony_ci case DA9211_REG_EVENT_B: 6162306a36Sopenharmony_ci return true; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci return false; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic const struct regmap_config da9211_regmap_config = { 6762306a36Sopenharmony_ci .reg_bits = 8, 6862306a36Sopenharmony_ci .val_bits = 8, 6962306a36Sopenharmony_ci .max_register = 5 * 128, 7062306a36Sopenharmony_ci .volatile_reg = da9211_volatile_reg, 7162306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 7262306a36Sopenharmony_ci .ranges = da9211_regmap_range, 7362306a36Sopenharmony_ci .num_ranges = ARRAY_SIZE(da9211_regmap_range), 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* Default limits measured in millivolts and milliamps */ 7762306a36Sopenharmony_ci#define DA9211_MIN_MV 300 7862306a36Sopenharmony_ci#define DA9211_MAX_MV 1570 7962306a36Sopenharmony_ci#define DA9211_STEP_MV 10 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* Current limits for DA9211 buck (uA) indices 8262306a36Sopenharmony_ci * corresponds with register values 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_cistatic const int da9211_current_limits[] = { 8562306a36Sopenharmony_ci 2000000, 2200000, 2400000, 2600000, 2800000, 3000000, 3200000, 3400000, 8662306a36Sopenharmony_ci 3600000, 3800000, 4000000, 4200000, 4400000, 4600000, 4800000, 5000000 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci/* Current limits for DA9213 buck (uA) indices 8962306a36Sopenharmony_ci * corresponds with register values 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_cistatic const int da9213_current_limits[] = { 9262306a36Sopenharmony_ci 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 9362306a36Sopenharmony_ci 4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci/* Current limits for DA9215 buck (uA) indices 9662306a36Sopenharmony_ci * corresponds with register values 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_cistatic const int da9215_current_limits[] = { 9962306a36Sopenharmony_ci 4000000, 4200000, 4400000, 4600000, 4800000, 5000000, 5200000, 5400000, 10062306a36Sopenharmony_ci 5600000, 5800000, 6000000, 6200000, 6400000, 6600000, 6800000, 7000000 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic unsigned int da9211_map_buck_mode(unsigned int mode) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci switch (mode) { 10662306a36Sopenharmony_ci case DA9211_BUCK_MODE_SLEEP: 10762306a36Sopenharmony_ci return REGULATOR_MODE_STANDBY; 10862306a36Sopenharmony_ci case DA9211_BUCK_MODE_SYNC: 10962306a36Sopenharmony_ci return REGULATOR_MODE_FAST; 11062306a36Sopenharmony_ci case DA9211_BUCK_MODE_AUTO: 11162306a36Sopenharmony_ci return REGULATOR_MODE_NORMAL; 11262306a36Sopenharmony_ci default: 11362306a36Sopenharmony_ci return REGULATOR_MODE_INVALID; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic unsigned int da9211_buck_get_mode(struct regulator_dev *rdev) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci int id = rdev_get_id(rdev); 12062306a36Sopenharmony_ci struct da9211 *chip = rdev_get_drvdata(rdev); 12162306a36Sopenharmony_ci unsigned int data; 12262306a36Sopenharmony_ci int ret, mode = 0; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci ret = regmap_read(chip->regmap, DA9211_REG_BUCKA_CONF+id, &data); 12562306a36Sopenharmony_ci if (ret < 0) 12662306a36Sopenharmony_ci return ret; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci switch (data & 0x03) { 12962306a36Sopenharmony_ci case DA9211_BUCK_MODE_SYNC: 13062306a36Sopenharmony_ci mode = REGULATOR_MODE_FAST; 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci case DA9211_BUCK_MODE_AUTO: 13362306a36Sopenharmony_ci mode = REGULATOR_MODE_NORMAL; 13462306a36Sopenharmony_ci break; 13562306a36Sopenharmony_ci case DA9211_BUCK_MODE_SLEEP: 13662306a36Sopenharmony_ci mode = REGULATOR_MODE_STANDBY; 13762306a36Sopenharmony_ci break; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return mode; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic int da9211_buck_set_mode(struct regulator_dev *rdev, 14462306a36Sopenharmony_ci unsigned int mode) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci int id = rdev_get_id(rdev); 14762306a36Sopenharmony_ci struct da9211 *chip = rdev_get_drvdata(rdev); 14862306a36Sopenharmony_ci int val = 0; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci switch (mode) { 15162306a36Sopenharmony_ci case REGULATOR_MODE_FAST: 15262306a36Sopenharmony_ci val = DA9211_BUCK_MODE_SYNC; 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 15562306a36Sopenharmony_ci val = DA9211_BUCK_MODE_AUTO; 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci case REGULATOR_MODE_STANDBY: 15862306a36Sopenharmony_ci val = DA9211_BUCK_MODE_SLEEP; 15962306a36Sopenharmony_ci break; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return regmap_update_bits(chip->regmap, DA9211_REG_BUCKA_CONF+id, 16362306a36Sopenharmony_ci 0x03, val); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int da9211_set_current_limit(struct regulator_dev *rdev, int min, 16762306a36Sopenharmony_ci int max) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci int id = rdev_get_id(rdev); 17062306a36Sopenharmony_ci struct da9211 *chip = rdev_get_drvdata(rdev); 17162306a36Sopenharmony_ci int i, max_size; 17262306a36Sopenharmony_ci const int *current_limits; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci switch (chip->chip_id) { 17562306a36Sopenharmony_ci case DA9211: 17662306a36Sopenharmony_ci current_limits = da9211_current_limits; 17762306a36Sopenharmony_ci max_size = ARRAY_SIZE(da9211_current_limits)-1; 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci case DA9213: 18062306a36Sopenharmony_ci current_limits = da9213_current_limits; 18162306a36Sopenharmony_ci max_size = ARRAY_SIZE(da9213_current_limits)-1; 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci case DA9215: 18462306a36Sopenharmony_ci current_limits = da9215_current_limits; 18562306a36Sopenharmony_ci max_size = ARRAY_SIZE(da9215_current_limits)-1; 18662306a36Sopenharmony_ci break; 18762306a36Sopenharmony_ci default: 18862306a36Sopenharmony_ci return -EINVAL; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* search for closest to maximum */ 19262306a36Sopenharmony_ci for (i = max_size; i >= 0; i--) { 19362306a36Sopenharmony_ci if (min <= current_limits[i] && 19462306a36Sopenharmony_ci max >= current_limits[i]) { 19562306a36Sopenharmony_ci return regmap_update_bits(chip->regmap, 19662306a36Sopenharmony_ci DA9211_REG_BUCK_ILIM, 19762306a36Sopenharmony_ci (0x0F << id*4), (i << id*4)); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return -EINVAL; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int da9211_get_current_limit(struct regulator_dev *rdev) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci int id = rdev_get_id(rdev); 20762306a36Sopenharmony_ci struct da9211 *chip = rdev_get_drvdata(rdev); 20862306a36Sopenharmony_ci unsigned int data; 20962306a36Sopenharmony_ci int ret; 21062306a36Sopenharmony_ci const int *current_limits; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci switch (chip->chip_id) { 21362306a36Sopenharmony_ci case DA9211: 21462306a36Sopenharmony_ci current_limits = da9211_current_limits; 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci case DA9213: 21762306a36Sopenharmony_ci current_limits = da9213_current_limits; 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci case DA9215: 22062306a36Sopenharmony_ci current_limits = da9215_current_limits; 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci default: 22362306a36Sopenharmony_ci return -EINVAL; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci ret = regmap_read(chip->regmap, DA9211_REG_BUCK_ILIM, &data); 22762306a36Sopenharmony_ci if (ret < 0) 22862306a36Sopenharmony_ci return ret; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* select one of 16 values: 0000 (2000mA or 3000mA) 23162306a36Sopenharmony_ci * to 1111 (5000mA or 6000mA). 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci data = (data >> id*4) & 0x0F; 23462306a36Sopenharmony_ci return current_limits[data]; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic const struct regulator_ops da9211_buck_ops = { 23862306a36Sopenharmony_ci .get_mode = da9211_buck_get_mode, 23962306a36Sopenharmony_ci .set_mode = da9211_buck_set_mode, 24062306a36Sopenharmony_ci .enable = regulator_enable_regmap, 24162306a36Sopenharmony_ci .disable = regulator_disable_regmap, 24262306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 24362306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 24462306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 24562306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 24662306a36Sopenharmony_ci .set_current_limit = da9211_set_current_limit, 24762306a36Sopenharmony_ci .get_current_limit = da9211_get_current_limit, 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci#define DA9211_BUCK(_id) \ 25162306a36Sopenharmony_ci{\ 25262306a36Sopenharmony_ci .name = #_id,\ 25362306a36Sopenharmony_ci .ops = &da9211_buck_ops,\ 25462306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE,\ 25562306a36Sopenharmony_ci .id = DA9211_ID_##_id,\ 25662306a36Sopenharmony_ci .n_voltages = (DA9211_MAX_MV - DA9211_MIN_MV) / DA9211_STEP_MV + 1,\ 25762306a36Sopenharmony_ci .min_uV = (DA9211_MIN_MV * 1000),\ 25862306a36Sopenharmony_ci .uV_step = (DA9211_STEP_MV * 1000),\ 25962306a36Sopenharmony_ci .enable_reg = DA9211_REG_BUCKA_CONT + DA9211_ID_##_id,\ 26062306a36Sopenharmony_ci .enable_mask = DA9211_BUCKA_EN,\ 26162306a36Sopenharmony_ci .vsel_reg = DA9211_REG_VBUCKA_A + DA9211_ID_##_id * 2,\ 26262306a36Sopenharmony_ci .vsel_mask = DA9211_VBUCK_MASK,\ 26362306a36Sopenharmony_ci .owner = THIS_MODULE,\ 26462306a36Sopenharmony_ci .of_map_mode = da9211_map_buck_mode,\ 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic struct regulator_desc da9211_regulators[] = { 26862306a36Sopenharmony_ci DA9211_BUCK(BUCKA), 26962306a36Sopenharmony_ci DA9211_BUCK(BUCKB), 27062306a36Sopenharmony_ci}; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci#ifdef CONFIG_OF 27362306a36Sopenharmony_cistatic struct of_regulator_match da9211_matches[] = { 27462306a36Sopenharmony_ci [DA9211_ID_BUCKA] = { 27562306a36Sopenharmony_ci .name = "BUCKA", 27662306a36Sopenharmony_ci .desc = &da9211_regulators[DA9211_ID_BUCKA], 27762306a36Sopenharmony_ci }, 27862306a36Sopenharmony_ci [DA9211_ID_BUCKB] = { 27962306a36Sopenharmony_ci .name = "BUCKB", 28062306a36Sopenharmony_ci .desc = &da9211_regulators[DA9211_ID_BUCKB], 28162306a36Sopenharmony_ci }, 28262306a36Sopenharmony_ci }; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic struct da9211_pdata *da9211_parse_regulators_dt( 28562306a36Sopenharmony_ci struct device *dev) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct da9211_pdata *pdata; 28862306a36Sopenharmony_ci struct device_node *node; 28962306a36Sopenharmony_ci int i, num, n; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci node = of_get_child_by_name(dev->of_node, "regulators"); 29262306a36Sopenharmony_ci if (!node) { 29362306a36Sopenharmony_ci dev_err(dev, "regulators node not found\n"); 29462306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci num = of_regulator_match(dev, node, da9211_matches, 29862306a36Sopenharmony_ci ARRAY_SIZE(da9211_matches)); 29962306a36Sopenharmony_ci of_node_put(node); 30062306a36Sopenharmony_ci if (num < 0) { 30162306a36Sopenharmony_ci dev_err(dev, "Failed to match regulators\n"); 30262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 30662306a36Sopenharmony_ci if (!pdata) 30762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci pdata->num_buck = num; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci n = 0; 31262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(da9211_matches); i++) { 31362306a36Sopenharmony_ci if (!da9211_matches[i].init_data) 31462306a36Sopenharmony_ci continue; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci pdata->init_data[n] = da9211_matches[i].init_data; 31762306a36Sopenharmony_ci pdata->reg_node[n] = da9211_matches[i].of_node; 31862306a36Sopenharmony_ci pdata->gpiod_ren[n] = devm_fwnode_gpiod_get(dev, 31962306a36Sopenharmony_ci of_fwnode_handle(pdata->reg_node[n]), 32062306a36Sopenharmony_ci "enable", 32162306a36Sopenharmony_ci GPIOD_OUT_HIGH | 32262306a36Sopenharmony_ci GPIOD_FLAGS_BIT_NONEXCLUSIVE, 32362306a36Sopenharmony_ci "da9211-enable"); 32462306a36Sopenharmony_ci if (IS_ERR(pdata->gpiod_ren[n])) 32562306a36Sopenharmony_ci pdata->gpiod_ren[n] = NULL; 32662306a36Sopenharmony_ci n++; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return pdata; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci#else 33262306a36Sopenharmony_cistatic struct da9211_pdata *da9211_parse_regulators_dt( 33362306a36Sopenharmony_ci struct device *dev) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci#endif 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic irqreturn_t da9211_irq_handler(int irq, void *data) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct da9211 *chip = data; 34262306a36Sopenharmony_ci int reg_val, err, ret = IRQ_NONE; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci err = regmap_read(chip->regmap, DA9211_REG_EVENT_B, ®_val); 34562306a36Sopenharmony_ci if (err < 0) 34662306a36Sopenharmony_ci goto error_i2c; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (reg_val & DA9211_E_OV_CURR_A) { 34962306a36Sopenharmony_ci regulator_notifier_call_chain(chip->rdev[0], 35062306a36Sopenharmony_ci REGULATOR_EVENT_OVER_CURRENT, NULL); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci err = regmap_write(chip->regmap, DA9211_REG_EVENT_B, 35362306a36Sopenharmony_ci DA9211_E_OV_CURR_A); 35462306a36Sopenharmony_ci if (err < 0) 35562306a36Sopenharmony_ci goto error_i2c; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci ret = IRQ_HANDLED; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (reg_val & DA9211_E_OV_CURR_B) { 36162306a36Sopenharmony_ci regulator_notifier_call_chain(chip->rdev[1], 36262306a36Sopenharmony_ci REGULATOR_EVENT_OVER_CURRENT, NULL); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci err = regmap_write(chip->regmap, DA9211_REG_EVENT_B, 36562306a36Sopenharmony_ci DA9211_E_OV_CURR_B); 36662306a36Sopenharmony_ci if (err < 0) 36762306a36Sopenharmony_ci goto error_i2c; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci ret = IRQ_HANDLED; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return ret; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cierror_i2c: 37562306a36Sopenharmony_ci dev_err(chip->dev, "I2C error : %d\n", err); 37662306a36Sopenharmony_ci return IRQ_NONE; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic int da9211_regulator_init(struct da9211 *chip) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct regulator_config config = { }; 38262306a36Sopenharmony_ci int i, ret; 38362306a36Sopenharmony_ci unsigned int data; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci ret = regmap_read(chip->regmap, DA9211_REG_CONFIG_E, &data); 38662306a36Sopenharmony_ci if (ret < 0) { 38762306a36Sopenharmony_ci dev_err(chip->dev, "Failed to read CONFIG_E reg: %d\n", ret); 38862306a36Sopenharmony_ci return ret; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci data &= DA9211_SLAVE_SEL; 39262306a36Sopenharmony_ci /* If configuration for 1/2 bucks is different between platform data 39362306a36Sopenharmony_ci * and the register, driver should exit. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci if (chip->pdata->num_buck == 1 && data == 0x00) 39662306a36Sopenharmony_ci chip->num_regulator = 1; 39762306a36Sopenharmony_ci else if (chip->pdata->num_buck == 2 && data != 0x00) 39862306a36Sopenharmony_ci chip->num_regulator = 2; 39962306a36Sopenharmony_ci else { 40062306a36Sopenharmony_ci dev_err(chip->dev, "Configuration is mismatched\n"); 40162306a36Sopenharmony_ci return -EINVAL; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci for (i = 0; i < chip->num_regulator; i++) { 40562306a36Sopenharmony_ci config.init_data = chip->pdata->init_data[i]; 40662306a36Sopenharmony_ci config.dev = chip->dev; 40762306a36Sopenharmony_ci config.driver_data = chip; 40862306a36Sopenharmony_ci config.regmap = chip->regmap; 40962306a36Sopenharmony_ci config.of_node = chip->pdata->reg_node[i]; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (chip->pdata->gpiod_ren[i]) 41262306a36Sopenharmony_ci config.ena_gpiod = chip->pdata->gpiod_ren[i]; 41362306a36Sopenharmony_ci else 41462306a36Sopenharmony_ci config.ena_gpiod = NULL; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* 41762306a36Sopenharmony_ci * Hand the GPIO descriptor management over to the regulator 41862306a36Sopenharmony_ci * core, remove it from GPIO devres management. 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci if (config.ena_gpiod) 42162306a36Sopenharmony_ci devm_gpiod_unhinge(chip->dev, config.ena_gpiod); 42262306a36Sopenharmony_ci chip->rdev[i] = devm_regulator_register(chip->dev, 42362306a36Sopenharmony_ci &da9211_regulators[i], &config); 42462306a36Sopenharmony_ci if (IS_ERR(chip->rdev[i])) { 42562306a36Sopenharmony_ci dev_err(chip->dev, 42662306a36Sopenharmony_ci "Failed to register DA9211 regulator\n"); 42762306a36Sopenharmony_ci return PTR_ERR(chip->rdev[i]); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (chip->chip_irq != 0) { 43162306a36Sopenharmony_ci ret = regmap_update_bits(chip->regmap, 43262306a36Sopenharmony_ci DA9211_REG_MASK_B, DA9211_M_OV_CURR_A << i, 0); 43362306a36Sopenharmony_ci if (ret < 0) { 43462306a36Sopenharmony_ci dev_err(chip->dev, 43562306a36Sopenharmony_ci "Failed to update mask reg: %d\n", ret); 43662306a36Sopenharmony_ci return ret; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return 0; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci/* 44562306a36Sopenharmony_ci * I2C driver interface functions 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_cistatic int da9211_i2c_probe(struct i2c_client *i2c) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci struct da9211 *chip; 45062306a36Sopenharmony_ci int error, ret; 45162306a36Sopenharmony_ci unsigned int data; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci chip = devm_kzalloc(&i2c->dev, sizeof(struct da9211), GFP_KERNEL); 45462306a36Sopenharmony_ci if (!chip) 45562306a36Sopenharmony_ci return -ENOMEM; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci chip->dev = &i2c->dev; 45862306a36Sopenharmony_ci chip->regmap = devm_regmap_init_i2c(i2c, &da9211_regmap_config); 45962306a36Sopenharmony_ci if (IS_ERR(chip->regmap)) { 46062306a36Sopenharmony_ci error = PTR_ERR(chip->regmap); 46162306a36Sopenharmony_ci dev_err(chip->dev, "Failed to allocate register map: %d\n", 46262306a36Sopenharmony_ci error); 46362306a36Sopenharmony_ci return error; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci i2c_set_clientdata(i2c, chip); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci chip->pdata = i2c->dev.platform_data; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci ret = regmap_read(chip->regmap, DA9211_REG_DEVICE_ID, &data); 47162306a36Sopenharmony_ci if (ret < 0) { 47262306a36Sopenharmony_ci dev_err(chip->dev, "Failed to read DEVICE_ID reg: %d\n", ret); 47362306a36Sopenharmony_ci return ret; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci switch (data) { 47762306a36Sopenharmony_ci case DA9211_DEVICE_ID: 47862306a36Sopenharmony_ci chip->chip_id = DA9211; 47962306a36Sopenharmony_ci break; 48062306a36Sopenharmony_ci case DA9213_DEVICE_ID: 48162306a36Sopenharmony_ci chip->chip_id = DA9213; 48262306a36Sopenharmony_ci break; 48362306a36Sopenharmony_ci case DA9215_DEVICE_ID: 48462306a36Sopenharmony_ci chip->chip_id = DA9215; 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci default: 48762306a36Sopenharmony_ci dev_err(chip->dev, "Unsupported device id = 0x%x.\n", data); 48862306a36Sopenharmony_ci return -ENODEV; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (!chip->pdata) 49262306a36Sopenharmony_ci chip->pdata = da9211_parse_regulators_dt(chip->dev); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (IS_ERR(chip->pdata)) { 49562306a36Sopenharmony_ci dev_err(chip->dev, "No regulators defined for the platform\n"); 49662306a36Sopenharmony_ci return PTR_ERR(chip->pdata); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci chip->chip_irq = i2c->irq; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci ret = da9211_regulator_init(chip); 50262306a36Sopenharmony_ci if (ret < 0) { 50362306a36Sopenharmony_ci dev_err(chip->dev, "Failed to initialize regulator: %d\n", ret); 50462306a36Sopenharmony_ci return ret; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (chip->chip_irq != 0) { 50862306a36Sopenharmony_ci ret = devm_request_threaded_irq(chip->dev, chip->chip_irq, NULL, 50962306a36Sopenharmony_ci da9211_irq_handler, 51062306a36Sopenharmony_ci IRQF_TRIGGER_LOW|IRQF_ONESHOT, 51162306a36Sopenharmony_ci "da9211", chip); 51262306a36Sopenharmony_ci if (ret != 0) { 51362306a36Sopenharmony_ci dev_err(chip->dev, "Failed to request IRQ: %d\n", 51462306a36Sopenharmony_ci chip->chip_irq); 51562306a36Sopenharmony_ci return ret; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci } else { 51862306a36Sopenharmony_ci dev_warn(chip->dev, "No IRQ configured\n"); 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return ret; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic const struct i2c_device_id da9211_i2c_id[] = { 52562306a36Sopenharmony_ci {"da9211", DA9211}, 52662306a36Sopenharmony_ci {"da9212", DA9212}, 52762306a36Sopenharmony_ci {"da9213", DA9213}, 52862306a36Sopenharmony_ci {"da9223", DA9223}, 52962306a36Sopenharmony_ci {"da9214", DA9214}, 53062306a36Sopenharmony_ci {"da9224", DA9224}, 53162306a36Sopenharmony_ci {"da9215", DA9215}, 53262306a36Sopenharmony_ci {"da9225", DA9225}, 53362306a36Sopenharmony_ci {}, 53462306a36Sopenharmony_ci}; 53562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, da9211_i2c_id); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci#ifdef CONFIG_OF 53862306a36Sopenharmony_cistatic const struct of_device_id da9211_dt_ids[] = { 53962306a36Sopenharmony_ci { .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] }, 54062306a36Sopenharmony_ci { .compatible = "dlg,da9212", .data = &da9211_i2c_id[1] }, 54162306a36Sopenharmony_ci { .compatible = "dlg,da9213", .data = &da9211_i2c_id[2] }, 54262306a36Sopenharmony_ci { .compatible = "dlg,da9223", .data = &da9211_i2c_id[3] }, 54362306a36Sopenharmony_ci { .compatible = "dlg,da9214", .data = &da9211_i2c_id[4] }, 54462306a36Sopenharmony_ci { .compatible = "dlg,da9224", .data = &da9211_i2c_id[5] }, 54562306a36Sopenharmony_ci { .compatible = "dlg,da9215", .data = &da9211_i2c_id[6] }, 54662306a36Sopenharmony_ci { .compatible = "dlg,da9225", .data = &da9211_i2c_id[7] }, 54762306a36Sopenharmony_ci {}, 54862306a36Sopenharmony_ci}; 54962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, da9211_dt_ids); 55062306a36Sopenharmony_ci#endif 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic struct i2c_driver da9211_regulator_driver = { 55362306a36Sopenharmony_ci .driver = { 55462306a36Sopenharmony_ci .name = "da9211", 55562306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 55662306a36Sopenharmony_ci .of_match_table = of_match_ptr(da9211_dt_ids), 55762306a36Sopenharmony_ci }, 55862306a36Sopenharmony_ci .probe = da9211_i2c_probe, 55962306a36Sopenharmony_ci .id_table = da9211_i2c_id, 56062306a36Sopenharmony_ci}; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cimodule_i2c_driver(da9211_regulator_driver); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ciMODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>"); 56562306a36Sopenharmony_ciMODULE_DESCRIPTION("DA9211/DA9212/DA9213/DA9223/DA9214/DA9224/DA9215/DA9225 regulator driver"); 56662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 567