brintos

brintos / linux-shallow public Read only

0
0
Text · 6.0 KiB · 39ade0d Raw
226 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// da9210-regulator.c - Regulator device driver for DA92104// Copyright (C) 2013  Dialog Semiconductor Ltd.5 6#include <linux/err.h>7#include <linux/i2c.h>8#include <linux/module.h>9#include <linux/interrupt.h>10#include <linux/irq.h>11#include <linux/regulator/driver.h>12#include <linux/regulator/machine.h>13#include <linux/of.h>14#include <linux/regulator/of_regulator.h>15#include <linux/regmap.h>16 17#include "da9210-regulator.h"18 19struct da9210 {20	struct regulator_dev *rdev;21	struct regmap *regmap;22};23 24static const struct regmap_config da9210_regmap_config = {25	.reg_bits = 8,26	.val_bits = 8,27};28 29static const struct regulator_ops da9210_buck_ops = {30	.enable = regulator_enable_regmap,31	.disable = regulator_disable_regmap,32	.is_enabled = regulator_is_enabled_regmap,33	.set_voltage_sel = regulator_set_voltage_sel_regmap,34	.get_voltage_sel = regulator_get_voltage_sel_regmap,35	.list_voltage = regulator_list_voltage_linear,36	.set_current_limit = regulator_set_current_limit_regmap,37	.get_current_limit = regulator_get_current_limit_regmap,38};39 40/* Default limits measured in millivolts and milliamps */41#define DA9210_MIN_MV		30042#define DA9210_MAX_MV		157043#define DA9210_STEP_MV		1044 45/* Current limits for buck (uA) indices corresponds with register values */46static const unsigned int da9210_buck_limits[] = {47	1600000, 1800000, 2000000, 2200000, 2400000, 2600000, 2800000, 3000000,48	3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 460000049};50 51static const struct regulator_desc da9210_reg = {52	.name = "DA9210",53	.id = 0,54	.ops = &da9210_buck_ops,55	.type = REGULATOR_VOLTAGE,56	.n_voltages = ((DA9210_MAX_MV - DA9210_MIN_MV) / DA9210_STEP_MV) + 1,57	.min_uV = (DA9210_MIN_MV * 1000),58	.uV_step = (DA9210_STEP_MV * 1000),59	.vsel_reg = DA9210_REG_VBUCK_A,60	.vsel_mask = DA9210_VBUCK_MASK,61	.enable_reg = DA9210_REG_BUCK_CONT,62	.enable_mask = DA9210_BUCK_EN,63	.owner = THIS_MODULE,64	.curr_table = da9210_buck_limits,65	.n_current_limits = ARRAY_SIZE(da9210_buck_limits),66	.csel_reg = DA9210_REG_BUCK_ILIM,67	.csel_mask = DA9210_BUCK_ILIM_MASK,68};69 70static irqreturn_t da9210_irq_handler(int irq, void *data)71{72	struct da9210 *chip = data;73	unsigned int val, handled = 0;74	int error, ret = IRQ_NONE;75 76	error = regmap_read(chip->regmap, DA9210_REG_EVENT_B, &val);77	if (error < 0)78		goto error_i2c;79 80	if (val & DA9210_E_OVCURR) {81		regulator_notifier_call_chain(chip->rdev,82					      REGULATOR_EVENT_OVER_CURRENT,83					      NULL);84		handled |= DA9210_E_OVCURR;85	}86	if (val & DA9210_E_NPWRGOOD) {87		regulator_notifier_call_chain(chip->rdev,88					      REGULATOR_EVENT_UNDER_VOLTAGE,89					      NULL);90		handled |= DA9210_E_NPWRGOOD;91	}92	if (val & (DA9210_E_TEMP_WARN | DA9210_E_TEMP_CRIT)) {93		regulator_notifier_call_chain(chip->rdev,94					      REGULATOR_EVENT_OVER_TEMP, NULL);95		handled |= val & (DA9210_E_TEMP_WARN | DA9210_E_TEMP_CRIT);96	}97	if (val & DA9210_E_VMAX) {98		regulator_notifier_call_chain(chip->rdev,99					      REGULATOR_EVENT_REGULATION_OUT,100					      NULL);101		handled |= DA9210_E_VMAX;102	}103 104	if (handled) {105		/* Clear handled events */106		error = regmap_write(chip->regmap, DA9210_REG_EVENT_B, handled);107		if (error < 0)108			goto error_i2c;109 110		ret = IRQ_HANDLED;111	}112 113	return ret;114 115error_i2c:116	dev_err(regmap_get_device(chip->regmap), "I2C error : %d\n", error);117	return ret;118}119 120/*121 * I2C driver interface functions122 */123 124static const struct of_device_id __maybe_unused da9210_dt_ids[] = {125	{ .compatible = "dlg,da9210", },126	{ }127};128MODULE_DEVICE_TABLE(of, da9210_dt_ids);129 130static int da9210_i2c_probe(struct i2c_client *i2c)131{132	struct da9210 *chip;133	struct device *dev = &i2c->dev;134	struct da9210_pdata *pdata = dev_get_platdata(dev);135	struct regulator_dev *rdev = NULL;136	struct regulator_config config = { };137	int error;138 139	chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL);140	if (!chip)141		return -ENOMEM;142 143	chip->regmap = devm_regmap_init_i2c(i2c, &da9210_regmap_config);144	if (IS_ERR(chip->regmap)) {145		error = PTR_ERR(chip->regmap);146		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",147			error);148		return error;149	}150 151	config.dev = &i2c->dev;152	config.init_data = pdata ? &pdata->da9210_constraints :153		of_get_regulator_init_data(dev, dev->of_node, &da9210_reg);154	config.driver_data = chip;155	config.regmap = chip->regmap;156	config.of_node = dev->of_node;157 158	/* Mask all interrupt sources to deassert interrupt line */159	error = regmap_write(chip->regmap, DA9210_REG_MASK_A, ~0);160	if (!error)161		error = regmap_write(chip->regmap, DA9210_REG_MASK_B, ~0);162	if (error) {163		dev_err(&i2c->dev, "Failed to write to mask reg: %d\n", error);164		return error;165	}166 167	rdev = devm_regulator_register(&i2c->dev, &da9210_reg, &config);168	if (IS_ERR(rdev)) {169		dev_err(&i2c->dev, "Failed to register DA9210 regulator\n");170		return PTR_ERR(rdev);171	}172 173	chip->rdev = rdev;174	if (i2c->irq) {175		error = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,176						  da9210_irq_handler,177						  IRQF_TRIGGER_LOW |178						  IRQF_ONESHOT | IRQF_SHARED,179						  "da9210", chip);180		if (error) {181			dev_err(&i2c->dev, "Failed to request IRQ%u: %d\n",182				i2c->irq, error);183			return error;184		}185 186		error = regmap_update_bits(chip->regmap, DA9210_REG_MASK_B,187					 DA9210_M_OVCURR | DA9210_M_NPWRGOOD |188					 DA9210_M_TEMP_WARN |189					 DA9210_M_TEMP_CRIT | DA9210_M_VMAX, 0);190		if (error < 0) {191			dev_err(&i2c->dev, "Failed to update mask reg: %d\n",192				error);193			return error;194		}195	} else {196		dev_warn(&i2c->dev, "No IRQ configured\n");197	}198 199	i2c_set_clientdata(i2c, chip);200 201	return 0;202}203 204static const struct i2c_device_id da9210_i2c_id[] = {205	{ "da9210" },206	{}207};208 209MODULE_DEVICE_TABLE(i2c, da9210_i2c_id);210 211static struct i2c_driver da9210_regulator_driver = {212	.driver = {213		.name = "da9210",214		.probe_type = PROBE_PREFER_ASYNCHRONOUS,215		.of_match_table = of_match_ptr(da9210_dt_ids),216	},217	.probe = da9210_i2c_probe,218	.id_table = da9210_i2c_id,219};220 221module_i2c_driver(da9210_regulator_driver);222 223MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");224MODULE_DESCRIPTION("Regulator device driver for Dialog DA9210");225MODULE_LICENSE("GPL v2");226