162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/delay.h> 462306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 562306a36Sopenharmony_ci#include <linux/i2c.h> 662306a36Sopenharmony_ci#include <linux/interrupt.h> 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/property.h> 1062306a36Sopenharmony_ci#include <linux/regmap.h> 1162306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define RTMV20_REG_DEVINFO 0x00 1462306a36Sopenharmony_ci#define RTMV20_REG_PULSEDELAY 0x01 1562306a36Sopenharmony_ci#define RTMV20_REG_PULSEWIDTH 0x03 1662306a36Sopenharmony_ci#define RTMV20_REG_LDCTRL1 0x05 1762306a36Sopenharmony_ci#define RTMV20_REG_ESPULSEWIDTH 0x06 1862306a36Sopenharmony_ci#define RTMV20_REG_ESLDCTRL1 0x08 1962306a36Sopenharmony_ci#define RTMV20_REG_LBP 0x0A 2062306a36Sopenharmony_ci#define RTMV20_REG_LDCTRL2 0x0B 2162306a36Sopenharmony_ci#define RTMV20_REG_FSIN1CTRL1 0x0D 2262306a36Sopenharmony_ci#define RTMV20_REG_FSIN1CTRL3 0x0F 2362306a36Sopenharmony_ci#define RTMV20_REG_FSIN2CTRL1 0x10 2462306a36Sopenharmony_ci#define RTMV20_REG_FSIN2CTRL3 0x12 2562306a36Sopenharmony_ci#define RTMV20_REG_ENCTRL 0x13 2662306a36Sopenharmony_ci#define RTMV20_REG_STRBVSYNDLYL 0x29 2762306a36Sopenharmony_ci#define RTMV20_REG_LDIRQ 0x30 2862306a36Sopenharmony_ci#define RTMV20_REG_LDSTAT 0x40 2962306a36Sopenharmony_ci#define RTMV20_REG_LDMASK 0x50 3062306a36Sopenharmony_ci#define RTMV20_MAX_REGS (RTMV20_REG_LDMASK + 1) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define RTMV20_VID_MASK GENMASK(7, 4) 3362306a36Sopenharmony_ci#define RICHTEK_VID 0x80 3462306a36Sopenharmony_ci#define RTMV20_LDCURR_MASK GENMASK(7, 0) 3562306a36Sopenharmony_ci#define RTMV20_DELAY_MASK GENMASK(9, 0) 3662306a36Sopenharmony_ci#define RTMV20_WIDTH_MASK GENMASK(13, 0) 3762306a36Sopenharmony_ci#define RTMV20_WIDTH2_MASK GENMASK(7, 0) 3862306a36Sopenharmony_ci#define RTMV20_LBPLVL_MASK GENMASK(3, 0) 3962306a36Sopenharmony_ci#define RTMV20_LBPEN_MASK BIT(7) 4062306a36Sopenharmony_ci#define RTMV20_STROBEPOL_MASK BIT(0) 4162306a36Sopenharmony_ci#define RTMV20_VSYNPOL_MASK BIT(1) 4262306a36Sopenharmony_ci#define RTMV20_FSINEN_MASK BIT(7) 4362306a36Sopenharmony_ci#define RTMV20_ESEN_MASK BIT(6) 4462306a36Sopenharmony_ci#define RTMV20_FSINOUT_MASK BIT(2) 4562306a36Sopenharmony_ci#define LDENABLE_MASK (BIT(3) | BIT(0)) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define OTPEVT_MASK BIT(4) 4862306a36Sopenharmony_ci#define SHORTEVT_MASK BIT(3) 4962306a36Sopenharmony_ci#define OPENEVT_MASK BIT(2) 5062306a36Sopenharmony_ci#define LBPEVT_MASK BIT(1) 5162306a36Sopenharmony_ci#define OCPEVT_MASK BIT(0) 5262306a36Sopenharmony_ci#define FAILEVT_MASK (SHORTEVT_MASK | OPENEVT_MASK | LBPEVT_MASK) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define RTMV20_LSW_MINUA 0 5562306a36Sopenharmony_ci#define RTMV20_LSW_MAXUA 6000000 5662306a36Sopenharmony_ci#define RTMV20_LSW_STEPUA 30000 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define RTMV20_LSW_DEFAULTUA 3000000 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define RTMV20_I2CRDY_TIMEUS 200 6162306a36Sopenharmony_ci#define RTMV20_CSRDY_TIMEUS 2000 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct rtmv20_priv { 6462306a36Sopenharmony_ci struct device *dev; 6562306a36Sopenharmony_ci struct regmap *regmap; 6662306a36Sopenharmony_ci struct gpio_desc *enable_gpio; 6762306a36Sopenharmony_ci struct regulator_dev *rdev; 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic int rtmv20_lsw_enable(struct regulator_dev *rdev) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct rtmv20_priv *priv = rdev_get_drvdata(rdev); 7362306a36Sopenharmony_ci int ret; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci gpiod_set_value(priv->enable_gpio, 1); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Wait for I2C can be accessed */ 7862306a36Sopenharmony_ci usleep_range(RTMV20_I2CRDY_TIMEUS, RTMV20_I2CRDY_TIMEUS + 100); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* HW re-enable, disable cache only and sync regcache here */ 8162306a36Sopenharmony_ci regcache_cache_only(priv->regmap, false); 8262306a36Sopenharmony_ci ret = regcache_sync(priv->regmap); 8362306a36Sopenharmony_ci if (ret) 8462306a36Sopenharmony_ci return ret; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return regulator_enable_regmap(rdev); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic int rtmv20_lsw_disable(struct regulator_dev *rdev) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct rtmv20_priv *priv = rdev_get_drvdata(rdev); 9262306a36Sopenharmony_ci int ret; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci ret = regulator_disable_regmap(rdev); 9562306a36Sopenharmony_ci if (ret) 9662306a36Sopenharmony_ci return ret; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* Mark the regcache as dirty and cache only before HW disabled */ 9962306a36Sopenharmony_ci regcache_cache_only(priv->regmap, true); 10062306a36Sopenharmony_ci regcache_mark_dirty(priv->regmap); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci gpiod_set_value(priv->enable_gpio, 0); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic int rtmv20_lsw_set_current_limit(struct regulator_dev *rdev, int min_uA, 10862306a36Sopenharmony_ci int max_uA) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci int sel; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (min_uA > RTMV20_LSW_MAXUA || max_uA < RTMV20_LSW_MINUA) 11362306a36Sopenharmony_ci return -EINVAL; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (max_uA > RTMV20_LSW_MAXUA) 11662306a36Sopenharmony_ci max_uA = RTMV20_LSW_MAXUA; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci sel = (max_uA - RTMV20_LSW_MINUA) / RTMV20_LSW_STEPUA; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* Ensure the selected setting is still in range */ 12162306a36Sopenharmony_ci if ((sel * RTMV20_LSW_STEPUA + RTMV20_LSW_MINUA) < min_uA) 12262306a36Sopenharmony_ci return -EINVAL; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci sel <<= ffs(rdev->desc->csel_mask) - 1; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return regmap_update_bits(rdev->regmap, rdev->desc->csel_reg, 12762306a36Sopenharmony_ci rdev->desc->csel_mask, sel); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int rtmv20_lsw_get_current_limit(struct regulator_dev *rdev) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci unsigned int val; 13362306a36Sopenharmony_ci int ret; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci ret = regmap_read(rdev->regmap, rdev->desc->csel_reg, &val); 13662306a36Sopenharmony_ci if (ret) 13762306a36Sopenharmony_ci return ret; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci val &= rdev->desc->csel_mask; 14062306a36Sopenharmony_ci val >>= ffs(rdev->desc->csel_mask) - 1; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return val * RTMV20_LSW_STEPUA + RTMV20_LSW_MINUA; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic const struct regulator_ops rtmv20_regulator_ops = { 14662306a36Sopenharmony_ci .set_current_limit = rtmv20_lsw_set_current_limit, 14762306a36Sopenharmony_ci .get_current_limit = rtmv20_lsw_get_current_limit, 14862306a36Sopenharmony_ci .enable = rtmv20_lsw_enable, 14962306a36Sopenharmony_ci .disable = rtmv20_lsw_disable, 15062306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic const struct regulator_desc rtmv20_lsw_desc = { 15462306a36Sopenharmony_ci .name = "rtmv20,lsw", 15562306a36Sopenharmony_ci .of_match = of_match_ptr("lsw"), 15662306a36Sopenharmony_ci .type = REGULATOR_CURRENT, 15762306a36Sopenharmony_ci .owner = THIS_MODULE, 15862306a36Sopenharmony_ci .ops = &rtmv20_regulator_ops, 15962306a36Sopenharmony_ci .csel_reg = RTMV20_REG_LDCTRL1, 16062306a36Sopenharmony_ci .csel_mask = RTMV20_LDCURR_MASK, 16162306a36Sopenharmony_ci .enable_reg = RTMV20_REG_ENCTRL, 16262306a36Sopenharmony_ci .enable_mask = LDENABLE_MASK, 16362306a36Sopenharmony_ci .enable_time = RTMV20_CSRDY_TIMEUS, 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic irqreturn_t rtmv20_irq_handler(int irq, void *data) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct rtmv20_priv *priv = data; 16962306a36Sopenharmony_ci unsigned int val; 17062306a36Sopenharmony_ci int ret; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci ret = regmap_read(priv->regmap, RTMV20_REG_LDIRQ, &val); 17362306a36Sopenharmony_ci if (ret) { 17462306a36Sopenharmony_ci dev_err(priv->dev, "Failed to get irq flags\n"); 17562306a36Sopenharmony_ci return IRQ_NONE; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (val & OTPEVT_MASK) 17962306a36Sopenharmony_ci regulator_notifier_call_chain(priv->rdev, REGULATOR_EVENT_OVER_TEMP, NULL); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (val & OCPEVT_MASK) 18262306a36Sopenharmony_ci regulator_notifier_call_chain(priv->rdev, REGULATOR_EVENT_OVER_CURRENT, NULL); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (val & FAILEVT_MASK) 18562306a36Sopenharmony_ci regulator_notifier_call_chain(priv->rdev, REGULATOR_EVENT_FAIL, NULL); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return IRQ_HANDLED; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic u32 clamp_to_selector(u32 val, u32 min, u32 max, u32 step) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci u32 retval = clamp_val(val, min, max); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return (retval - min) / step; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int rtmv20_properties_init(struct rtmv20_priv *priv) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci const struct { 20062306a36Sopenharmony_ci const char *name; 20162306a36Sopenharmony_ci u32 def; 20262306a36Sopenharmony_ci u32 min; 20362306a36Sopenharmony_ci u32 max; 20462306a36Sopenharmony_ci u32 step; 20562306a36Sopenharmony_ci u32 addr; 20662306a36Sopenharmony_ci u32 mask; 20762306a36Sopenharmony_ci } props[] = { 20862306a36Sopenharmony_ci { "richtek,ld-pulse-delay-us", 0, 0, 100000, 100, RTMV20_REG_PULSEDELAY, 20962306a36Sopenharmony_ci RTMV20_DELAY_MASK }, 21062306a36Sopenharmony_ci { "richtek,ld-pulse-width-us", 1200, 0, 10000, 1, RTMV20_REG_PULSEWIDTH, 21162306a36Sopenharmony_ci RTMV20_WIDTH_MASK }, 21262306a36Sopenharmony_ci { "richtek,fsin1-delay-us", 23000, 0, 100000, 100, RTMV20_REG_FSIN1CTRL1, 21362306a36Sopenharmony_ci RTMV20_DELAY_MASK }, 21462306a36Sopenharmony_ci { "richtek,fsin1-width-us", 160, 40, 10000, 40, RTMV20_REG_FSIN1CTRL3, 21562306a36Sopenharmony_ci RTMV20_WIDTH2_MASK }, 21662306a36Sopenharmony_ci { "richtek,fsin2-delay-us", 23000, 0, 100000, 100, RTMV20_REG_FSIN2CTRL1, 21762306a36Sopenharmony_ci RTMV20_DELAY_MASK }, 21862306a36Sopenharmony_ci { "richtek,fsin2-width-us", 160, 40, 10000, 40, RTMV20_REG_FSIN2CTRL3, 21962306a36Sopenharmony_ci RTMV20_WIDTH2_MASK }, 22062306a36Sopenharmony_ci { "richtek,es-pulse-width-us", 1200, 0, 10000, 1, RTMV20_REG_ESPULSEWIDTH, 22162306a36Sopenharmony_ci RTMV20_WIDTH_MASK }, 22262306a36Sopenharmony_ci { "richtek,es-ld-current-microamp", 3000000, 0, 6000000, 30000, 22362306a36Sopenharmony_ci RTMV20_REG_ESLDCTRL1, RTMV20_LDCURR_MASK }, 22462306a36Sopenharmony_ci { "richtek,lbp-level-microvolt", 2700000, 2400000, 3700000, 100000, RTMV20_REG_LBP, 22562306a36Sopenharmony_ci RTMV20_LBPLVL_MASK }, 22662306a36Sopenharmony_ci { "richtek,lbp-enable", 0, 0, 1, 1, RTMV20_REG_LBP, RTMV20_LBPEN_MASK }, 22762306a36Sopenharmony_ci { "richtek,strobe-polarity-high", 1, 0, 1, 1, RTMV20_REG_LDCTRL2, 22862306a36Sopenharmony_ci RTMV20_STROBEPOL_MASK }, 22962306a36Sopenharmony_ci { "richtek,vsync-polarity-high", 1, 0, 1, 1, RTMV20_REG_LDCTRL2, 23062306a36Sopenharmony_ci RTMV20_VSYNPOL_MASK }, 23162306a36Sopenharmony_ci { "richtek,fsin-enable", 0, 0, 1, 1, RTMV20_REG_ENCTRL, RTMV20_FSINEN_MASK }, 23262306a36Sopenharmony_ci { "richtek,fsin-output", 0, 0, 1, 1, RTMV20_REG_ENCTRL, RTMV20_FSINOUT_MASK }, 23362306a36Sopenharmony_ci { "richtek,es-enable", 0, 0, 1, 1, RTMV20_REG_ENCTRL, RTMV20_ESEN_MASK }, 23462306a36Sopenharmony_ci }; 23562306a36Sopenharmony_ci int i, ret; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(props); i++) { 23862306a36Sopenharmony_ci __be16 bval16; 23962306a36Sopenharmony_ci u16 val16; 24062306a36Sopenharmony_ci u32 temp; 24162306a36Sopenharmony_ci int significant_bit = fls(props[i].mask); 24262306a36Sopenharmony_ci int shift = ffs(props[i].mask) - 1; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (props[i].max > 1) { 24562306a36Sopenharmony_ci ret = device_property_read_u32(priv->dev, props[i].name, &temp); 24662306a36Sopenharmony_ci if (ret) 24762306a36Sopenharmony_ci temp = props[i].def; 24862306a36Sopenharmony_ci } else 24962306a36Sopenharmony_ci temp = device_property_read_bool(priv->dev, props[i].name); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci temp = clamp_to_selector(temp, props[i].min, props[i].max, props[i].step); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* If significant bit is over 8, two byte access, others one */ 25462306a36Sopenharmony_ci if (significant_bit > 8) { 25562306a36Sopenharmony_ci ret = regmap_raw_read(priv->regmap, props[i].addr, &bval16, sizeof(bval16)); 25662306a36Sopenharmony_ci if (ret) 25762306a36Sopenharmony_ci return ret; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci val16 = be16_to_cpu(bval16); 26062306a36Sopenharmony_ci val16 &= ~props[i].mask; 26162306a36Sopenharmony_ci val16 |= (temp << shift); 26262306a36Sopenharmony_ci bval16 = cpu_to_be16(val16); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci ret = regmap_raw_write(priv->regmap, props[i].addr, &bval16, 26562306a36Sopenharmony_ci sizeof(bval16)); 26662306a36Sopenharmony_ci } else { 26762306a36Sopenharmony_ci ret = regmap_update_bits(priv->regmap, props[i].addr, props[i].mask, 26862306a36Sopenharmony_ci temp << shift); 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (ret) 27262306a36Sopenharmony_ci return ret; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int rtmv20_check_chip_exist(struct rtmv20_priv *priv) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci unsigned int val; 28162306a36Sopenharmony_ci int ret; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci ret = regmap_read(priv->regmap, RTMV20_REG_DEVINFO, &val); 28462306a36Sopenharmony_ci if (ret) 28562306a36Sopenharmony_ci return ret; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if ((val & RTMV20_VID_MASK) != RICHTEK_VID) 28862306a36Sopenharmony_ci return -ENODEV; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic bool rtmv20_is_accessible_reg(struct device *dev, unsigned int reg) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci switch (reg) { 29662306a36Sopenharmony_ci case RTMV20_REG_DEVINFO ... RTMV20_REG_STRBVSYNDLYL: 29762306a36Sopenharmony_ci case RTMV20_REG_LDIRQ: 29862306a36Sopenharmony_ci case RTMV20_REG_LDSTAT: 29962306a36Sopenharmony_ci case RTMV20_REG_LDMASK: 30062306a36Sopenharmony_ci return true; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci return false; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic bool rtmv20_is_volatile_reg(struct device *dev, unsigned int reg) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci if (reg == RTMV20_REG_LDIRQ || reg == RTMV20_REG_LDSTAT) 30862306a36Sopenharmony_ci return true; 30962306a36Sopenharmony_ci return false; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic const struct regmap_config rtmv20_regmap_config = { 31362306a36Sopenharmony_ci .reg_bits = 8, 31462306a36Sopenharmony_ci .val_bits = 8, 31562306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 31662306a36Sopenharmony_ci .max_register = RTMV20_REG_LDMASK, 31762306a36Sopenharmony_ci .num_reg_defaults_raw = RTMV20_MAX_REGS, 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci .writeable_reg = rtmv20_is_accessible_reg, 32062306a36Sopenharmony_ci .readable_reg = rtmv20_is_accessible_reg, 32162306a36Sopenharmony_ci .volatile_reg = rtmv20_is_volatile_reg, 32262306a36Sopenharmony_ci}; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int rtmv20_probe(struct i2c_client *i2c) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct rtmv20_priv *priv; 32762306a36Sopenharmony_ci struct regulator_config config = {}; 32862306a36Sopenharmony_ci int ret; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); 33162306a36Sopenharmony_ci if (!priv) 33262306a36Sopenharmony_ci return -ENOMEM; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci priv->dev = &i2c->dev; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Before regmap register, configure HW enable to make I2C accessible */ 33762306a36Sopenharmony_ci priv->enable_gpio = devm_gpiod_get(&i2c->dev, "enable", GPIOD_OUT_HIGH); 33862306a36Sopenharmony_ci if (IS_ERR(priv->enable_gpio)) { 33962306a36Sopenharmony_ci dev_err(&i2c->dev, "Failed to get enable gpio\n"); 34062306a36Sopenharmony_ci return PTR_ERR(priv->enable_gpio); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* Wait for I2C can be accessed */ 34462306a36Sopenharmony_ci usleep_range(RTMV20_I2CRDY_TIMEUS, RTMV20_I2CRDY_TIMEUS + 100); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci priv->regmap = devm_regmap_init_i2c(i2c, &rtmv20_regmap_config); 34762306a36Sopenharmony_ci if (IS_ERR(priv->regmap)) { 34862306a36Sopenharmony_ci dev_err(&i2c->dev, "Failed to allocate register map\n"); 34962306a36Sopenharmony_ci return PTR_ERR(priv->regmap); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci ret = rtmv20_check_chip_exist(priv); 35362306a36Sopenharmony_ci if (ret) { 35462306a36Sopenharmony_ci dev_err(&i2c->dev, "Chip vendor info is not matched\n"); 35562306a36Sopenharmony_ci return ret; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ret = rtmv20_properties_init(priv); 35962306a36Sopenharmony_ci if (ret) { 36062306a36Sopenharmony_ci dev_err(&i2c->dev, "Failed to init properties\n"); 36162306a36Sopenharmony_ci return ret; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* 36562306a36Sopenharmony_ci * keep in shutdown mode to minimize the current consumption 36662306a36Sopenharmony_ci * and also mark regcache as dirty 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci regcache_cache_only(priv->regmap, true); 36962306a36Sopenharmony_ci regcache_mark_dirty(priv->regmap); 37062306a36Sopenharmony_ci gpiod_set_value(priv->enable_gpio, 0); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci config.dev = &i2c->dev; 37362306a36Sopenharmony_ci config.regmap = priv->regmap; 37462306a36Sopenharmony_ci config.driver_data = priv; 37562306a36Sopenharmony_ci priv->rdev = devm_regulator_register(&i2c->dev, &rtmv20_lsw_desc, &config); 37662306a36Sopenharmony_ci if (IS_ERR(priv->rdev)) { 37762306a36Sopenharmony_ci dev_err(&i2c->dev, "Failed to register regulator\n"); 37862306a36Sopenharmony_ci return PTR_ERR(priv->rdev); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* Unmask all events before IRQ registered */ 38262306a36Sopenharmony_ci ret = regmap_write(priv->regmap, RTMV20_REG_LDMASK, 0); 38362306a36Sopenharmony_ci if (ret) 38462306a36Sopenharmony_ci return ret; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci return devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, rtmv20_irq_handler, 38762306a36Sopenharmony_ci IRQF_ONESHOT, dev_name(&i2c->dev), priv); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic int __maybe_unused rtmv20_suspend(struct device *dev) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct i2c_client *i2c = to_i2c_client(dev); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* 39562306a36Sopenharmony_ci * When system suspend, disable irq to prevent interrupt trigger 39662306a36Sopenharmony_ci * during I2C bus suspend 39762306a36Sopenharmony_ci */ 39862306a36Sopenharmony_ci disable_irq(i2c->irq); 39962306a36Sopenharmony_ci if (device_may_wakeup(dev)) 40062306a36Sopenharmony_ci enable_irq_wake(i2c->irq); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic int __maybe_unused rtmv20_resume(struct device *dev) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct i2c_client *i2c = to_i2c_client(dev); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* Enable irq after I2C bus already resume */ 41062306a36Sopenharmony_ci enable_irq(i2c->irq); 41162306a36Sopenharmony_ci if (device_may_wakeup(dev)) 41262306a36Sopenharmony_ci disable_irq_wake(i2c->irq); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci return 0; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(rtmv20_pm, rtmv20_suspend, rtmv20_resume); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic const struct of_device_id __maybe_unused rtmv20_of_id[] = { 42062306a36Sopenharmony_ci { .compatible = "richtek,rtmv20", }, 42162306a36Sopenharmony_ci {} 42262306a36Sopenharmony_ci}; 42362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rtmv20_of_id); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic struct i2c_driver rtmv20_driver = { 42662306a36Sopenharmony_ci .driver = { 42762306a36Sopenharmony_ci .name = "rtmv20", 42862306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 42962306a36Sopenharmony_ci .of_match_table = of_match_ptr(rtmv20_of_id), 43062306a36Sopenharmony_ci .pm = &rtmv20_pm, 43162306a36Sopenharmony_ci }, 43262306a36Sopenharmony_ci .probe = rtmv20_probe, 43362306a36Sopenharmony_ci}; 43462306a36Sopenharmony_cimodule_i2c_driver(rtmv20_driver); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ciMODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); 43762306a36Sopenharmony_ciMODULE_DESCRIPTION("Richtek RTMV20 Regulator Driver"); 43862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 439