392 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3#include <linux/bits.h>4#include <linux/gpio/consumer.h>5#include <linux/interrupt.h>6#include <linux/kernel.h>7#include <linux/mod_devicetable.h>8#include <linux/module.h>9#include <linux/of.h>10#include <linux/platform_device.h>11#include <linux/regmap.h>12#include <linux/regulator/driver.h>13#include <linux/regulator/machine.h>14 15enum {16 MT6370_IDX_DSVBOOST = 0,17 MT6370_IDX_DSVPOS,18 MT6370_IDX_DSVNEG,19 MT6370_IDX_VIBLDO,20 MT6370_MAX_IDX21};22 23#define MT6370_REG_LDO_CFG 0x18024#define MT6370_REG_LDO_VOUT 0x18125#define MT6370_REG_DB_CTRL1 0x1B026#define MT6370_REG_DB_CTRL2 0x1B127#define MT6370_REG_DB_VBST 0x1B228#define MT6370_REG_DB_VPOS 0x1B329#define MT6370_REG_DB_VNEG 0x1B430#define MT6370_REG_LDO_STAT 0x1DC31#define MT6370_REG_DB_STAT 0x1DF32 33#define MT6370_LDOOMS_MASK BIT(7)34#define MT6370_LDOEN_MASK BIT(7)35#define MT6370_LDOVOUT_MASK GENMASK(3, 0)36#define MT6370_DBPERD_MASK (BIT(7) | BIT(4))37#define MT6370_DBEXTEN_MASK BIT(0)38#define MT6370_DBVPOSEN_MASK BIT(6)39#define MT6370_DBVPOSDISG_MASK BIT(5)40#define MT6370_DBVNEGEN_MASK BIT(3)41#define MT6370_DBVNEGDISG_MASK BIT(2)42#define MT6370_DBALLON_MASK (MT6370_DBVPOSEN_MASK | MT6370_DBVNEGEN_MASK)43#define MT6370_DBSLEW_MASK GENMASK(7, 6)44#define MT6370_DBVOUT_MASK GENMASK(5, 0)45#define MT6370_LDOOC_EVT_MASK BIT(7)46#define MT6370_POSSCP_EVT_MASK BIT(7)47#define MT6370_NEGSCP_EVT_MASK BIT(6)48#define MT6370_BSTOCP_EVT_MASK BIT(5)49#define MT6370_POSOCP_EVT_MASK BIT(4)50#define MT6370_NEGOCP_EVT_MASK BIT(3)51 52#define MT6370_LDO_MINUV 160000053#define MT6370_LDO_STPUV 20000054#define MT6370_LDO_N_VOLT 1355#define MT6370_DBVBOOST_MINUV 400000056#define MT6370_DBVBOOST_STPUV 5000057#define MT6370_DBVBOOST_N_VOLT 4558#define MT6370_DBVOUT_MINUV 400000059#define MT6370_DBVOUT_STPUV 5000060#define MT6370_DBVOUT_N_VOLT 4161 62struct mt6370_priv {63 struct device *dev;64 struct regmap *regmap;65 struct regulator_dev *rdev[MT6370_MAX_IDX];66 bool use_external_ctrl;67};68 69static const unsigned int mt6370_vpos_ramp_tbl[] = { 8540, 5840, 4830, 3000 };70static const unsigned int mt6370_vneg_ramp_tbl[] = { 10090, 6310, 5050, 3150 };71 72static int mt6370_get_error_flags(struct regulator_dev *rdev,73 unsigned int *flags)74{75 struct regmap *regmap = rdev_get_regmap(rdev);76 unsigned int stat_reg, stat, rpt_flags = 0;77 int rid = rdev_get_id(rdev), ret;78 79 if (rid == MT6370_IDX_VIBLDO)80 stat_reg = MT6370_REG_LDO_STAT;81 else82 stat_reg = MT6370_REG_DB_STAT;83 84 ret = regmap_read(regmap, stat_reg, &stat);85 if (ret)86 return ret;87 88 switch (rid) {89 case MT6370_IDX_DSVBOOST:90 if (stat & MT6370_BSTOCP_EVT_MASK)91 rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;92 break;93 case MT6370_IDX_DSVPOS:94 if (stat & MT6370_POSSCP_EVT_MASK)95 rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE;96 97 if (stat & MT6370_POSOCP_EVT_MASK)98 rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;99 break;100 case MT6370_IDX_DSVNEG:101 if (stat & MT6370_NEGSCP_EVT_MASK)102 rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE;103 104 if (stat & MT6370_NEGOCP_EVT_MASK)105 rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;106 break;107 default:108 if (stat & MT6370_LDOOC_EVT_MASK)109 rpt_flags |= REGULATOR_ERROR_OVER_CURRENT;110 break;111 }112 113 *flags = rpt_flags;114 return 0;115}116 117static const struct regulator_ops mt6370_dbvboost_ops = {118 .get_voltage_sel = regulator_get_voltage_sel_regmap,119 .set_voltage_sel = regulator_set_voltage_sel_regmap,120 .list_voltage = regulator_list_voltage_linear,121 .get_bypass = regulator_get_bypass_regmap,122 .set_bypass = regulator_set_bypass_regmap,123 .get_error_flags = mt6370_get_error_flags,124};125 126static const struct regulator_ops mt6370_dbvout_ops = {127 .get_voltage_sel = regulator_get_voltage_sel_regmap,128 .set_voltage_sel = regulator_set_voltage_sel_regmap,129 .list_voltage = regulator_list_voltage_linear,130 .is_enabled = regulator_is_enabled_regmap,131 .enable = regulator_enable_regmap,132 .disable = regulator_disable_regmap,133 .set_active_discharge = regulator_set_active_discharge_regmap,134 .set_ramp_delay = regulator_set_ramp_delay_regmap,135 .get_error_flags = mt6370_get_error_flags,136};137 138static const struct regulator_ops mt6370_ldo_ops = {139 .get_voltage_sel = regulator_get_voltage_sel_regmap,140 .set_voltage_sel = regulator_set_voltage_sel_regmap,141 .list_voltage = regulator_list_voltage_linear,142 .is_enabled = regulator_is_enabled_regmap,143 .enable = regulator_enable_regmap,144 .disable = regulator_disable_regmap,145 .set_active_discharge = regulator_set_active_discharge_regmap,146 .get_error_flags = mt6370_get_error_flags,147};148 149static int mt6370_of_parse_cb(struct device_node *np,150 const struct regulator_desc *desc,151 struct regulator_config *config)152{153 struct mt6370_priv *priv = config->driver_data;154 struct gpio_desc *enable_gpio;155 int ret;156 157 enable_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np), "enable", 0,158 GPIOD_OUT_HIGH |159 GPIOD_FLAGS_BIT_NONEXCLUSIVE,160 desc->name);161 if (IS_ERR(enable_gpio)) {162 config->ena_gpiod = NULL;163 return 0;164 }165 166 /*167 * RG control by default168 * Only if all are using external pin, change all by external control169 */170 if (priv->use_external_ctrl) {171 ret = regmap_update_bits(priv->regmap, MT6370_REG_DB_CTRL1,172 MT6370_DBEXTEN_MASK,173 MT6370_DBEXTEN_MASK);174 if (ret)175 return ret;176 }177 178 config->ena_gpiod = enable_gpio;179 priv->use_external_ctrl = true;180 return 0;181}182 183static const struct regulator_desc mt6370_regulator_descs[] = {184 {185 .name = "mt6370-dsv-vbst",186 .of_match = of_match_ptr("dsvbst"),187 .regulators_node = of_match_ptr("regulators"),188 .id = MT6370_IDX_DSVBOOST,189 .type = REGULATOR_VOLTAGE,190 .owner = THIS_MODULE,191 .ops = &mt6370_dbvboost_ops,192 .min_uV = MT6370_DBVBOOST_MINUV,193 .uV_step = MT6370_DBVBOOST_STPUV,194 .n_voltages = MT6370_DBVBOOST_N_VOLT,195 .vsel_reg = MT6370_REG_DB_VBST,196 .vsel_mask = MT6370_DBVOUT_MASK,197 .bypass_reg = MT6370_REG_DB_CTRL1,198 .bypass_mask = MT6370_DBPERD_MASK,199 .bypass_val_on = MT6370_DBPERD_MASK,200 },201 {202 .name = "mt6370-dsv-vpos",203 .of_match = of_match_ptr("dsvpos"),204 .regulators_node = of_match_ptr("regulators"),205 .id = MT6370_IDX_DSVPOS,206 .type = REGULATOR_VOLTAGE,207 .owner = THIS_MODULE,208 .of_parse_cb = mt6370_of_parse_cb,209 .ops = &mt6370_dbvout_ops,210 .min_uV = MT6370_DBVOUT_MINUV,211 .uV_step = MT6370_DBVOUT_STPUV,212 .n_voltages = MT6370_DBVOUT_N_VOLT,213 .vsel_reg = MT6370_REG_DB_VPOS,214 .vsel_mask = MT6370_DBVOUT_MASK,215 .enable_reg = MT6370_REG_DB_CTRL2,216 .enable_mask = MT6370_DBVPOSEN_MASK,217 .ramp_reg = MT6370_REG_DB_VPOS,218 .ramp_mask = MT6370_DBSLEW_MASK,219 .ramp_delay_table = mt6370_vpos_ramp_tbl,220 .n_ramp_values = ARRAY_SIZE(mt6370_vpos_ramp_tbl),221 .active_discharge_reg = MT6370_REG_DB_CTRL2,222 .active_discharge_mask = MT6370_DBVPOSDISG_MASK,223 .active_discharge_on = MT6370_DBVPOSDISG_MASK,224 },225 {226 .name = "mt6370-dsv-vneg",227 .of_match = of_match_ptr("dsvneg"),228 .regulators_node = of_match_ptr("regulators"),229 .id = MT6370_IDX_DSVNEG,230 .type = REGULATOR_VOLTAGE,231 .owner = THIS_MODULE,232 .of_parse_cb = mt6370_of_parse_cb,233 .ops = &mt6370_dbvout_ops,234 .min_uV = MT6370_DBVOUT_MINUV,235 .uV_step = MT6370_DBVOUT_STPUV,236 .n_voltages = MT6370_DBVOUT_N_VOLT,237 .vsel_reg = MT6370_REG_DB_VNEG,238 .vsel_mask = MT6370_DBVOUT_MASK,239 .enable_reg = MT6370_REG_DB_CTRL2,240 .enable_mask = MT6370_DBVNEGEN_MASK,241 .ramp_reg = MT6370_REG_DB_VNEG,242 .ramp_mask = MT6370_DBSLEW_MASK,243 .ramp_delay_table = mt6370_vneg_ramp_tbl,244 .n_ramp_values = ARRAY_SIZE(mt6370_vneg_ramp_tbl),245 .active_discharge_reg = MT6370_REG_DB_CTRL2,246 .active_discharge_mask = MT6370_DBVNEGDISG_MASK,247 .active_discharge_on = MT6370_DBVNEGDISG_MASK,248 },249 {250 .name = "mt6370-vib-ldo",251 .of_match = of_match_ptr("vibldo"),252 .regulators_node = of_match_ptr("regulators"),253 .id = MT6370_IDX_VIBLDO,254 .type = REGULATOR_VOLTAGE,255 .owner = THIS_MODULE,256 .ops = &mt6370_ldo_ops,257 .min_uV = MT6370_LDO_MINUV,258 .uV_step = MT6370_LDO_STPUV,259 .n_voltages = MT6370_LDO_N_VOLT,260 .vsel_reg = MT6370_REG_LDO_VOUT,261 .vsel_mask = MT6370_LDOVOUT_MASK,262 .enable_reg = MT6370_REG_LDO_VOUT,263 .enable_mask = MT6370_LDOEN_MASK,264 .active_discharge_reg = MT6370_REG_LDO_CFG,265 .active_discharge_mask = MT6370_LDOOMS_MASK,266 .active_discharge_on = MT6370_LDOOMS_MASK,267 }268};269 270static irqreturn_t mt6370_scp_handler(int irq, void *data)271{272 struct regulator_dev *rdev = data;273 274 regulator_notifier_call_chain(rdev, REGULATOR_EVENT_UNDER_VOLTAGE,275 NULL);276 return IRQ_HANDLED;277}278 279static irqreturn_t mt6370_ocp_handler(int irq, void *data)280{281 struct regulator_dev *rdev = data;282 283 regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL);284 return IRQ_HANDLED;285}286 287static int mt6370_regulator_irq_register(struct mt6370_priv *priv)288{289 struct platform_device *pdev = to_platform_device(priv->dev);290 static const struct {291 const char *name;292 int rid;293 irq_handler_t handler;294 } mt6370_irqs[] = {295 { "db_vpos_scp", MT6370_IDX_DSVPOS, mt6370_scp_handler },296 { "db_vneg_scp", MT6370_IDX_DSVNEG, mt6370_scp_handler },297 { "db_vbst_ocp", MT6370_IDX_DSVBOOST, mt6370_ocp_handler },298 { "db_vpos_ocp", MT6370_IDX_DSVPOS, mt6370_ocp_handler },299 { "db_vneg_ocp", MT6370_IDX_DSVNEG, mt6370_ocp_handler },300 { "ldo_oc", MT6370_IDX_VIBLDO, mt6370_ocp_handler }301 };302 struct regulator_dev *rdev;303 int i, irq, ret;304 305 for (i = 0; i < ARRAY_SIZE(mt6370_irqs); i++) {306 irq = platform_get_irq_byname(pdev, mt6370_irqs[i].name);307 308 rdev = priv->rdev[mt6370_irqs[i].rid];309 310 ret = devm_request_threaded_irq(priv->dev, irq, NULL,311 mt6370_irqs[i].handler, 0,312 mt6370_irqs[i].name, rdev);313 if (ret) {314 dev_err(priv->dev,315 "Failed to register (%d) interrupt\n", i);316 return ret;317 }318 }319 320 return 0;321}322 323static int mt6370_regualtor_register(struct mt6370_priv *priv)324{325 struct regulator_dev *rdev;326 struct regulator_config cfg = {};327 struct device *parent = priv->dev->parent;328 int i;329 330 cfg.dev = parent;331 cfg.driver_data = priv;332 333 for (i = 0; i < MT6370_MAX_IDX; i++) {334 rdev = devm_regulator_register(priv->dev,335 mt6370_regulator_descs + i,336 &cfg);337 if (IS_ERR(rdev)) {338 dev_err(priv->dev,339 "Failed to register (%d) regulator\n", i);340 return PTR_ERR(rdev);341 }342 343 priv->rdev[i] = rdev;344 }345 346 return 0;347}348 349static int mt6370_regulator_probe(struct platform_device *pdev)350{351 struct mt6370_priv *priv;352 int ret;353 354 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);355 if (!priv)356 return -ENOMEM;357 358 priv->dev = &pdev->dev;359 360 priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);361 if (!priv->regmap) {362 dev_err(&pdev->dev, "Failed to init regmap\n");363 return -ENODEV;364 }365 366 ret = mt6370_regualtor_register(priv);367 if (ret)368 return ret;369 370 return mt6370_regulator_irq_register(priv);371}372 373static const struct platform_device_id mt6370_devid_table[] = {374 { "mt6370-regulator", 0},375 {}376};377MODULE_DEVICE_TABLE(platform, mt6370_devid_table);378 379static struct platform_driver mt6370_regulator_driver = {380 .driver = {381 .name = "mt6370-regulator",382 .probe_type = PROBE_PREFER_ASYNCHRONOUS,383 },384 .id_table = mt6370_devid_table,385 .probe = mt6370_regulator_probe,386};387module_platform_driver(mt6370_regulator_driver);388 389MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");390MODULE_DESCRIPTION("Mediatek MT6370 Regulator Driver");391MODULE_LICENSE("GPL v2");392