18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * LP8755 High Performance Power Management Unit : System Interface Driver
48c2ecf20Sopenharmony_ci * (based on rev. 0.26)
58c2ecf20Sopenharmony_ci * Copyright 2012 Texas Instruments
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Daniel(Geon Si) Jeong <daniel.jeong@ti.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/i2c.h>
138c2ecf20Sopenharmony_ci#include <linux/err.h>
148c2ecf20Sopenharmony_ci#include <linux/irq.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci#include <linux/gpio.h>
178c2ecf20Sopenharmony_ci#include <linux/regmap.h>
188c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
198c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h>
208c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h>
218c2ecf20Sopenharmony_ci#include <linux/platform_data/lp8755.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define LP8755_REG_BUCK0	0x00
248c2ecf20Sopenharmony_ci#define LP8755_REG_BUCK1	0x03
258c2ecf20Sopenharmony_ci#define LP8755_REG_BUCK2	0x04
268c2ecf20Sopenharmony_ci#define LP8755_REG_BUCK3	0x01
278c2ecf20Sopenharmony_ci#define LP8755_REG_BUCK4	0x05
288c2ecf20Sopenharmony_ci#define LP8755_REG_BUCK5	0x02
298c2ecf20Sopenharmony_ci#define LP8755_REG_MAX		0xFF
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define LP8755_BUCK_EN_M	BIT(7)
328c2ecf20Sopenharmony_ci#define LP8755_BUCK_LINEAR_OUT_MAX	0x76
338c2ecf20Sopenharmony_ci#define LP8755_BUCK_VOUT_M	0x7F
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct lp8755_mphase {
368c2ecf20Sopenharmony_ci	int nreg;
378c2ecf20Sopenharmony_ci	int buck_num[LP8755_BUCK_MAX];
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistruct lp8755_chip {
418c2ecf20Sopenharmony_ci	struct device *dev;
428c2ecf20Sopenharmony_ci	struct regmap *regmap;
438c2ecf20Sopenharmony_ci	struct lp8755_platform_data *pdata;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	int irq;
468c2ecf20Sopenharmony_ci	unsigned int irqmask;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	int mphase;
498c2ecf20Sopenharmony_ci	struct regulator_dev *rdev[LP8755_BUCK_MAX];
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic int lp8755_buck_enable_time(struct regulator_dev *rdev)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	int ret;
558c2ecf20Sopenharmony_ci	unsigned int regval;
568c2ecf20Sopenharmony_ci	enum lp8755_bucks id = rdev_get_id(rdev);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	ret = regmap_read(rdev->regmap, 0x12 + id, &regval);
598c2ecf20Sopenharmony_ci	if (ret < 0) {
608c2ecf20Sopenharmony_ci		dev_err(&rdev->dev, "i2c access error %s\n", __func__);
618c2ecf20Sopenharmony_ci		return ret;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci	return (regval & 0xff) * 100;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic int lp8755_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	int ret;
698c2ecf20Sopenharmony_ci	unsigned int regbval = 0x0;
708c2ecf20Sopenharmony_ci	enum lp8755_bucks id = rdev_get_id(rdev);
718c2ecf20Sopenharmony_ci	struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	switch (mode) {
748c2ecf20Sopenharmony_ci	case REGULATOR_MODE_FAST:
758c2ecf20Sopenharmony_ci		/* forced pwm mode */
768c2ecf20Sopenharmony_ci		regbval = (0x01 << id);
778c2ecf20Sopenharmony_ci		break;
788c2ecf20Sopenharmony_ci	case REGULATOR_MODE_NORMAL:
798c2ecf20Sopenharmony_ci		/* enable automatic pwm/pfm mode */
808c2ecf20Sopenharmony_ci		ret = regmap_update_bits(rdev->regmap, 0x08 + id, 0x20, 0x00);
818c2ecf20Sopenharmony_ci		if (ret < 0)
828c2ecf20Sopenharmony_ci			goto err_i2c;
838c2ecf20Sopenharmony_ci		break;
848c2ecf20Sopenharmony_ci	case REGULATOR_MODE_IDLE:
858c2ecf20Sopenharmony_ci		/* enable automatic pwm/pfm/lppfm mode */
868c2ecf20Sopenharmony_ci		ret = regmap_update_bits(rdev->regmap, 0x08 + id, 0x20, 0x20);
878c2ecf20Sopenharmony_ci		if (ret < 0)
888c2ecf20Sopenharmony_ci			goto err_i2c;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci		ret = regmap_update_bits(rdev->regmap, 0x10, 0x01, 0x01);
918c2ecf20Sopenharmony_ci		if (ret < 0)
928c2ecf20Sopenharmony_ci			goto err_i2c;
938c2ecf20Sopenharmony_ci		break;
948c2ecf20Sopenharmony_ci	default:
958c2ecf20Sopenharmony_ci		dev_err(pchip->dev, "Not supported buck mode %s\n", __func__);
968c2ecf20Sopenharmony_ci		/* forced pwm mode */
978c2ecf20Sopenharmony_ci		regbval = (0x01 << id);
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	ret = regmap_update_bits(rdev->regmap, 0x06, 0x01 << id, regbval);
1018c2ecf20Sopenharmony_ci	if (ret < 0)
1028c2ecf20Sopenharmony_ci		goto err_i2c;
1038c2ecf20Sopenharmony_ci	return ret;
1048c2ecf20Sopenharmony_cierr_i2c:
1058c2ecf20Sopenharmony_ci	dev_err(&rdev->dev, "i2c access error %s\n", __func__);
1068c2ecf20Sopenharmony_ci	return ret;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic unsigned int lp8755_buck_get_mode(struct regulator_dev *rdev)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	int ret;
1128c2ecf20Sopenharmony_ci	unsigned int regval;
1138c2ecf20Sopenharmony_ci	enum lp8755_bucks id = rdev_get_id(rdev);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	ret = regmap_read(rdev->regmap, 0x06, &regval);
1168c2ecf20Sopenharmony_ci	if (ret < 0)
1178c2ecf20Sopenharmony_ci		goto err_i2c;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	/* mode fast means forced pwm mode */
1208c2ecf20Sopenharmony_ci	if (regval & (0x01 << id))
1218c2ecf20Sopenharmony_ci		return REGULATOR_MODE_FAST;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	ret = regmap_read(rdev->regmap, 0x08 + id, &regval);
1248c2ecf20Sopenharmony_ci	if (ret < 0)
1258c2ecf20Sopenharmony_ci		goto err_i2c;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/* mode idle means automatic pwm/pfm/lppfm mode */
1288c2ecf20Sopenharmony_ci	if (regval & 0x20)
1298c2ecf20Sopenharmony_ci		return REGULATOR_MODE_IDLE;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* mode normal means automatic pwm/pfm mode */
1328c2ecf20Sopenharmony_ci	return REGULATOR_MODE_NORMAL;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cierr_i2c:
1358c2ecf20Sopenharmony_ci	dev_err(&rdev->dev, "i2c access error %s\n", __func__);
1368c2ecf20Sopenharmony_ci	return 0;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic int lp8755_buck_set_ramp(struct regulator_dev *rdev, int ramp)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	int ret;
1428c2ecf20Sopenharmony_ci	unsigned int regval = 0x00;
1438c2ecf20Sopenharmony_ci	enum lp8755_bucks id = rdev_get_id(rdev);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	/* uV/us */
1468c2ecf20Sopenharmony_ci	switch (ramp) {
1478c2ecf20Sopenharmony_ci	case 0 ... 230:
1488c2ecf20Sopenharmony_ci		regval = 0x07;
1498c2ecf20Sopenharmony_ci		break;
1508c2ecf20Sopenharmony_ci	case 231 ... 470:
1518c2ecf20Sopenharmony_ci		regval = 0x06;
1528c2ecf20Sopenharmony_ci		break;
1538c2ecf20Sopenharmony_ci	case 471 ... 940:
1548c2ecf20Sopenharmony_ci		regval = 0x05;
1558c2ecf20Sopenharmony_ci		break;
1568c2ecf20Sopenharmony_ci	case 941 ... 1900:
1578c2ecf20Sopenharmony_ci		regval = 0x04;
1588c2ecf20Sopenharmony_ci		break;
1598c2ecf20Sopenharmony_ci	case 1901 ... 3800:
1608c2ecf20Sopenharmony_ci		regval = 0x03;
1618c2ecf20Sopenharmony_ci		break;
1628c2ecf20Sopenharmony_ci	case 3801 ... 7500:
1638c2ecf20Sopenharmony_ci		regval = 0x02;
1648c2ecf20Sopenharmony_ci		break;
1658c2ecf20Sopenharmony_ci	case 7501 ... 15000:
1668c2ecf20Sopenharmony_ci		regval = 0x01;
1678c2ecf20Sopenharmony_ci		break;
1688c2ecf20Sopenharmony_ci	case 15001 ... 30000:
1698c2ecf20Sopenharmony_ci		regval = 0x00;
1708c2ecf20Sopenharmony_ci		break;
1718c2ecf20Sopenharmony_ci	default:
1728c2ecf20Sopenharmony_ci		dev_err(&rdev->dev,
1738c2ecf20Sopenharmony_ci			"Not supported ramp value %d %s\n", ramp, __func__);
1748c2ecf20Sopenharmony_ci		return -EINVAL;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	ret = regmap_update_bits(rdev->regmap, 0x07 + id, 0x07, regval);
1788c2ecf20Sopenharmony_ci	if (ret < 0)
1798c2ecf20Sopenharmony_ci		goto err_i2c;
1808c2ecf20Sopenharmony_ci	return ret;
1818c2ecf20Sopenharmony_cierr_i2c:
1828c2ecf20Sopenharmony_ci	dev_err(&rdev->dev, "i2c access error %s\n", __func__);
1838c2ecf20Sopenharmony_ci	return ret;
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic const struct regulator_ops lp8755_buck_ops = {
1878c2ecf20Sopenharmony_ci	.map_voltage = regulator_map_voltage_linear,
1888c2ecf20Sopenharmony_ci	.list_voltage = regulator_list_voltage_linear,
1898c2ecf20Sopenharmony_ci	.set_voltage_sel = regulator_set_voltage_sel_regmap,
1908c2ecf20Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
1918c2ecf20Sopenharmony_ci	.enable = regulator_enable_regmap,
1928c2ecf20Sopenharmony_ci	.disable = regulator_disable_regmap,
1938c2ecf20Sopenharmony_ci	.is_enabled = regulator_is_enabled_regmap,
1948c2ecf20Sopenharmony_ci	.enable_time = lp8755_buck_enable_time,
1958c2ecf20Sopenharmony_ci	.set_mode = lp8755_buck_set_mode,
1968c2ecf20Sopenharmony_ci	.get_mode = lp8755_buck_get_mode,
1978c2ecf20Sopenharmony_ci	.set_ramp_delay = lp8755_buck_set_ramp,
1988c2ecf20Sopenharmony_ci};
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci#define lp8755_rail(_id) "lp8755_buck"#_id
2018c2ecf20Sopenharmony_ci#define lp8755_buck_init(_id)\
2028c2ecf20Sopenharmony_ci{\
2038c2ecf20Sopenharmony_ci	.constraints = {\
2048c2ecf20Sopenharmony_ci		.name = lp8755_rail(_id),\
2058c2ecf20Sopenharmony_ci		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,\
2068c2ecf20Sopenharmony_ci		.min_uV = 500000,\
2078c2ecf20Sopenharmony_ci		.max_uV = 1675000,\
2088c2ecf20Sopenharmony_ci	},\
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic struct regulator_init_data lp8755_reg_default[LP8755_BUCK_MAX] = {
2128c2ecf20Sopenharmony_ci	[LP8755_BUCK0] = lp8755_buck_init(0),
2138c2ecf20Sopenharmony_ci	[LP8755_BUCK1] = lp8755_buck_init(1),
2148c2ecf20Sopenharmony_ci	[LP8755_BUCK2] = lp8755_buck_init(2),
2158c2ecf20Sopenharmony_ci	[LP8755_BUCK3] = lp8755_buck_init(3),
2168c2ecf20Sopenharmony_ci	[LP8755_BUCK4] = lp8755_buck_init(4),
2178c2ecf20Sopenharmony_ci	[LP8755_BUCK5] = lp8755_buck_init(5),
2188c2ecf20Sopenharmony_ci};
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic const struct lp8755_mphase mphase_buck[MPHASE_CONF_MAX] = {
2218c2ecf20Sopenharmony_ci	{ 3, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK5 } },
2228c2ecf20Sopenharmony_ci	{ 6, { LP8755_BUCK0, LP8755_BUCK1, LP8755_BUCK2, LP8755_BUCK3,
2238c2ecf20Sopenharmony_ci	       LP8755_BUCK4, LP8755_BUCK5 } },
2248c2ecf20Sopenharmony_ci	{ 5, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK4,
2258c2ecf20Sopenharmony_ci	       LP8755_BUCK5} },
2268c2ecf20Sopenharmony_ci	{ 4, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK4, LP8755_BUCK5} },
2278c2ecf20Sopenharmony_ci	{ 3, { LP8755_BUCK0, LP8755_BUCK4, LP8755_BUCK5} },
2288c2ecf20Sopenharmony_ci	{ 2, { LP8755_BUCK0, LP8755_BUCK5} },
2298c2ecf20Sopenharmony_ci	{ 1, { LP8755_BUCK0} },
2308c2ecf20Sopenharmony_ci	{ 2, { LP8755_BUCK0, LP8755_BUCK3} },
2318c2ecf20Sopenharmony_ci	{ 4, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK5} },
2328c2ecf20Sopenharmony_ci};
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic int lp8755_init_data(struct lp8755_chip *pchip)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	unsigned int regval;
2378c2ecf20Sopenharmony_ci	int ret, icnt, buck_num;
2388c2ecf20Sopenharmony_ci	struct lp8755_platform_data *pdata = pchip->pdata;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* read back  muti-phase configuration */
2418c2ecf20Sopenharmony_ci	ret = regmap_read(pchip->regmap, 0x3D, &regval);
2428c2ecf20Sopenharmony_ci	if (ret < 0)
2438c2ecf20Sopenharmony_ci		goto out_i2c_error;
2448c2ecf20Sopenharmony_ci	pchip->mphase = regval & 0x0F;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/* set default data based on multi-phase config */
2478c2ecf20Sopenharmony_ci	for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) {
2488c2ecf20Sopenharmony_ci		buck_num = mphase_buck[pchip->mphase].buck_num[icnt];
2498c2ecf20Sopenharmony_ci		pdata->buck_data[buck_num] = &lp8755_reg_default[buck_num];
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci	return ret;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ciout_i2c_error:
2548c2ecf20Sopenharmony_ci	dev_err(pchip->dev, "i2c access error %s\n", __func__);
2558c2ecf20Sopenharmony_ci	return ret;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci#define lp8755_buck_desc(_id)\
2598c2ecf20Sopenharmony_ci{\
2608c2ecf20Sopenharmony_ci	.name = lp8755_rail(_id),\
2618c2ecf20Sopenharmony_ci	.id   = LP8755_BUCK##_id,\
2628c2ecf20Sopenharmony_ci	.ops  = &lp8755_buck_ops,\
2638c2ecf20Sopenharmony_ci	.n_voltages = LP8755_BUCK_LINEAR_OUT_MAX+1,\
2648c2ecf20Sopenharmony_ci	.uV_step = 10000,\
2658c2ecf20Sopenharmony_ci	.min_uV = 500000,\
2668c2ecf20Sopenharmony_ci	.type = REGULATOR_VOLTAGE,\
2678c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,\
2688c2ecf20Sopenharmony_ci	.enable_reg = LP8755_REG_BUCK##_id,\
2698c2ecf20Sopenharmony_ci	.enable_mask = LP8755_BUCK_EN_M,\
2708c2ecf20Sopenharmony_ci	.vsel_reg = LP8755_REG_BUCK##_id,\
2718c2ecf20Sopenharmony_ci	.vsel_mask = LP8755_BUCK_VOUT_M,\
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic const struct regulator_desc lp8755_regulators[] = {
2758c2ecf20Sopenharmony_ci	lp8755_buck_desc(0),
2768c2ecf20Sopenharmony_ci	lp8755_buck_desc(1),
2778c2ecf20Sopenharmony_ci	lp8755_buck_desc(2),
2788c2ecf20Sopenharmony_ci	lp8755_buck_desc(3),
2798c2ecf20Sopenharmony_ci	lp8755_buck_desc(4),
2808c2ecf20Sopenharmony_ci	lp8755_buck_desc(5),
2818c2ecf20Sopenharmony_ci};
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic int lp8755_regulator_init(struct lp8755_chip *pchip)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	int ret, icnt, buck_num;
2868c2ecf20Sopenharmony_ci	struct lp8755_platform_data *pdata = pchip->pdata;
2878c2ecf20Sopenharmony_ci	struct regulator_config rconfig = { };
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	rconfig.regmap = pchip->regmap;
2908c2ecf20Sopenharmony_ci	rconfig.dev = pchip->dev;
2918c2ecf20Sopenharmony_ci	rconfig.driver_data = pchip;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) {
2948c2ecf20Sopenharmony_ci		buck_num = mphase_buck[pchip->mphase].buck_num[icnt];
2958c2ecf20Sopenharmony_ci		rconfig.init_data = pdata->buck_data[buck_num];
2968c2ecf20Sopenharmony_ci		rconfig.of_node = pchip->dev->of_node;
2978c2ecf20Sopenharmony_ci		pchip->rdev[buck_num] =
2988c2ecf20Sopenharmony_ci		    devm_regulator_register(pchip->dev,
2998c2ecf20Sopenharmony_ci				    &lp8755_regulators[buck_num], &rconfig);
3008c2ecf20Sopenharmony_ci		if (IS_ERR(pchip->rdev[buck_num])) {
3018c2ecf20Sopenharmony_ci			ret = PTR_ERR(pchip->rdev[buck_num]);
3028c2ecf20Sopenharmony_ci			pchip->rdev[buck_num] = NULL;
3038c2ecf20Sopenharmony_ci			dev_err(pchip->dev, "regulator init failed: buck %d\n",
3048c2ecf20Sopenharmony_ci				buck_num);
3058c2ecf20Sopenharmony_ci			return ret;
3068c2ecf20Sopenharmony_ci		}
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	return 0;
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic irqreturn_t lp8755_irq_handler(int irq, void *data)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	int ret, icnt;
3158c2ecf20Sopenharmony_ci	unsigned int flag0, flag1;
3168c2ecf20Sopenharmony_ci	struct lp8755_chip *pchip = data;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* read flag0 register */
3198c2ecf20Sopenharmony_ci	ret = regmap_read(pchip->regmap, 0x0D, &flag0);
3208c2ecf20Sopenharmony_ci	if (ret < 0)
3218c2ecf20Sopenharmony_ci		goto err_i2c;
3228c2ecf20Sopenharmony_ci	/* clear flag register to pull up int. pin */
3238c2ecf20Sopenharmony_ci	ret = regmap_write(pchip->regmap, 0x0D, 0x00);
3248c2ecf20Sopenharmony_ci	if (ret < 0)
3258c2ecf20Sopenharmony_ci		goto err_i2c;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* sent power fault detection event to specific regulator */
3288c2ecf20Sopenharmony_ci	for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
3298c2ecf20Sopenharmony_ci		if ((flag0 & (0x4 << icnt))
3308c2ecf20Sopenharmony_ci		    && (pchip->irqmask & (0x04 << icnt))
3318c2ecf20Sopenharmony_ci		    && (pchip->rdev[icnt] != NULL)) {
3328c2ecf20Sopenharmony_ci			regulator_notifier_call_chain(pchip->rdev[icnt],
3338c2ecf20Sopenharmony_ci						      LP8755_EVENT_PWR_FAULT,
3348c2ecf20Sopenharmony_ci						      NULL);
3358c2ecf20Sopenharmony_ci		}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* read flag1 register */
3388c2ecf20Sopenharmony_ci	ret = regmap_read(pchip->regmap, 0x0E, &flag1);
3398c2ecf20Sopenharmony_ci	if (ret < 0)
3408c2ecf20Sopenharmony_ci		goto err_i2c;
3418c2ecf20Sopenharmony_ci	/* clear flag register to pull up int. pin */
3428c2ecf20Sopenharmony_ci	ret = regmap_write(pchip->regmap, 0x0E, 0x00);
3438c2ecf20Sopenharmony_ci	if (ret < 0)
3448c2ecf20Sopenharmony_ci		goto err_i2c;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	/* send OCP event to all regulator devices */
3478c2ecf20Sopenharmony_ci	if ((flag1 & 0x01) && (pchip->irqmask & 0x01))
3488c2ecf20Sopenharmony_ci		for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
3498c2ecf20Sopenharmony_ci			if (pchip->rdev[icnt] != NULL) {
3508c2ecf20Sopenharmony_ci				regulator_notifier_call_chain(pchip->rdev[icnt],
3518c2ecf20Sopenharmony_ci							      LP8755_EVENT_OCP,
3528c2ecf20Sopenharmony_ci							      NULL);
3538c2ecf20Sopenharmony_ci			}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	/* send OVP event to all regulator devices */
3568c2ecf20Sopenharmony_ci	if ((flag1 & 0x02) && (pchip->irqmask & 0x02))
3578c2ecf20Sopenharmony_ci		for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
3588c2ecf20Sopenharmony_ci			if (pchip->rdev[icnt] != NULL) {
3598c2ecf20Sopenharmony_ci				regulator_notifier_call_chain(pchip->rdev[icnt],
3608c2ecf20Sopenharmony_ci							      LP8755_EVENT_OVP,
3618c2ecf20Sopenharmony_ci							      NULL);
3628c2ecf20Sopenharmony_ci			}
3638c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cierr_i2c:
3668c2ecf20Sopenharmony_ci	dev_err(pchip->dev, "i2c access error %s\n", __func__);
3678c2ecf20Sopenharmony_ci	return IRQ_NONE;
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic int lp8755_int_config(struct lp8755_chip *pchip)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	int ret;
3738c2ecf20Sopenharmony_ci	unsigned int regval;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (pchip->irq == 0) {
3768c2ecf20Sopenharmony_ci		dev_warn(pchip->dev, "not use interrupt : %s\n", __func__);
3778c2ecf20Sopenharmony_ci		return 0;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	ret = regmap_read(pchip->regmap, 0x0F, &regval);
3818c2ecf20Sopenharmony_ci	if (ret < 0) {
3828c2ecf20Sopenharmony_ci		dev_err(pchip->dev, "i2c access error %s\n", __func__);
3838c2ecf20Sopenharmony_ci		return ret;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	pchip->irqmask = regval;
3878c2ecf20Sopenharmony_ci	return devm_request_threaded_irq(pchip->dev, pchip->irq, NULL,
3888c2ecf20Sopenharmony_ci					 lp8755_irq_handler,
3898c2ecf20Sopenharmony_ci					 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
3908c2ecf20Sopenharmony_ci					 "lp8755-irq", pchip);
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic const struct regmap_config lp8755_regmap = {
3948c2ecf20Sopenharmony_ci	.reg_bits = 8,
3958c2ecf20Sopenharmony_ci	.val_bits = 8,
3968c2ecf20Sopenharmony_ci	.max_register = LP8755_REG_MAX,
3978c2ecf20Sopenharmony_ci};
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int lp8755_probe(struct i2c_client *client,
4008c2ecf20Sopenharmony_ci			const struct i2c_device_id *id)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	int ret, icnt;
4038c2ecf20Sopenharmony_ci	struct lp8755_chip *pchip;
4048c2ecf20Sopenharmony_ci	struct lp8755_platform_data *pdata = dev_get_platdata(&client->dev);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
4078c2ecf20Sopenharmony_ci		dev_err(&client->dev, "i2c functionality check fail.\n");
4088c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	pchip = devm_kzalloc(&client->dev,
4128c2ecf20Sopenharmony_ci			     sizeof(struct lp8755_chip), GFP_KERNEL);
4138c2ecf20Sopenharmony_ci	if (!pchip)
4148c2ecf20Sopenharmony_ci		return -ENOMEM;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	pchip->dev = &client->dev;
4178c2ecf20Sopenharmony_ci	pchip->regmap = devm_regmap_init_i2c(client, &lp8755_regmap);
4188c2ecf20Sopenharmony_ci	if (IS_ERR(pchip->regmap)) {
4198c2ecf20Sopenharmony_ci		ret = PTR_ERR(pchip->regmap);
4208c2ecf20Sopenharmony_ci		dev_err(&client->dev, "fail to allocate regmap %d\n", ret);
4218c2ecf20Sopenharmony_ci		return ret;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, pchip);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	if (pdata != NULL) {
4268c2ecf20Sopenharmony_ci		pchip->pdata = pdata;
4278c2ecf20Sopenharmony_ci		pchip->mphase = pdata->mphase;
4288c2ecf20Sopenharmony_ci	} else {
4298c2ecf20Sopenharmony_ci		pchip->pdata = devm_kzalloc(pchip->dev,
4308c2ecf20Sopenharmony_ci					    sizeof(struct lp8755_platform_data),
4318c2ecf20Sopenharmony_ci					    GFP_KERNEL);
4328c2ecf20Sopenharmony_ci		if (!pchip->pdata)
4338c2ecf20Sopenharmony_ci			return -ENOMEM;
4348c2ecf20Sopenharmony_ci		ret = lp8755_init_data(pchip);
4358c2ecf20Sopenharmony_ci		if (ret < 0) {
4368c2ecf20Sopenharmony_ci			dev_err(&client->dev, "fail to initialize chip\n");
4378c2ecf20Sopenharmony_ci			return ret;
4388c2ecf20Sopenharmony_ci		}
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	ret = lp8755_regulator_init(pchip);
4428c2ecf20Sopenharmony_ci	if (ret < 0) {
4438c2ecf20Sopenharmony_ci		dev_err(&client->dev, "fail to initialize regulators\n");
4448c2ecf20Sopenharmony_ci		goto err;
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	pchip->irq = client->irq;
4488c2ecf20Sopenharmony_ci	ret = lp8755_int_config(pchip);
4498c2ecf20Sopenharmony_ci	if (ret < 0) {
4508c2ecf20Sopenharmony_ci		dev_err(&client->dev, "fail to irq config\n");
4518c2ecf20Sopenharmony_ci		goto err;
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	return ret;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cierr:
4578c2ecf20Sopenharmony_ci	/* output disable */
4588c2ecf20Sopenharmony_ci	for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
4598c2ecf20Sopenharmony_ci		regmap_write(pchip->regmap, icnt, 0x00);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	return ret;
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic int lp8755_remove(struct i2c_client *client)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	int icnt;
4678c2ecf20Sopenharmony_ci	struct lp8755_chip *pchip = i2c_get_clientdata(client);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
4708c2ecf20Sopenharmony_ci		regmap_write(pchip->regmap, icnt, 0x00);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	return 0;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic const struct i2c_device_id lp8755_id[] = {
4768c2ecf20Sopenharmony_ci	{LP8755_NAME, 0},
4778c2ecf20Sopenharmony_ci	{}
4788c2ecf20Sopenharmony_ci};
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lp8755_id);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cistatic struct i2c_driver lp8755_i2c_driver = {
4838c2ecf20Sopenharmony_ci	.driver = {
4848c2ecf20Sopenharmony_ci		   .name = LP8755_NAME,
4858c2ecf20Sopenharmony_ci		   },
4868c2ecf20Sopenharmony_ci	.probe = lp8755_probe,
4878c2ecf20Sopenharmony_ci	.remove = lp8755_remove,
4888c2ecf20Sopenharmony_ci	.id_table = lp8755_id,
4898c2ecf20Sopenharmony_ci};
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic int __init lp8755_init(void)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	return i2c_add_driver(&lp8755_i2c_driver);
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cisubsys_initcall(lp8755_init);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistatic void __exit lp8755_exit(void)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	i2c_del_driver(&lp8755_i2c_driver);
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cimodule_exit(lp8755_exit);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Texas Instruments lp8755 driver");
5068c2ecf20Sopenharmony_ciMODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
5078c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
508