brintos

brintos / linux-shallow public Read only

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