mirror of https://github.com/OpenIPC/firmware.git
				
				
				
			
		
			
				
	
	
		
			217 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Diff
		
	
	
			
		
		
	
	
			217 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Diff
		
	
	
| diff -drupN a/drivers/mfd/rn5t567.c b/drivers/mfd/rn5t567.c
 | |
| --- a/drivers/mfd/rn5t567.c	1970-01-01 03:00:00.000000000 +0300
 | |
| +++ b/drivers/mfd/rn5t567.c	2022-06-09 05:02:30.000000000 +0300
 | |
| @@ -0,0 +1,212 @@
 | |
| +/*
 | |
| + * Core driver access RC5T567 power management chip.
 | |
| + *
 | |
| + * Copyright (C) 2016 Ingenic Semiconductor Co., Ltd.
 | |
| + * Author: cli <chen.li@ingenic.com>
 | |
| + *
 | |
| + * Based on code
 | |
| + *	drivers/mfd/rc5t583.c
 | |
| + *	Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
 | |
| + *	Author: Laxman dewangan <ldewangan@nvidia.com>
 | |
| + *
 | |
| + * This program is distributed in the hope that it will be useful, but WITHOUT
 | |
| + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | |
| + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | |
| + * more details.
 | |
| + *
 | |
| + * You should have received a copy of the GNU General Public License
 | |
| + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
| + *
 | |
| + */
 | |
| +#include <linux/interrupt.h>
 | |
| +#include <linux/irq.h>
 | |
| +#include <linux/kernel.h>
 | |
| +#include <linux/module.h>
 | |
| +#include <linux/init.h>
 | |
| +#include <linux/err.h>
 | |
| +#include <linux/slab.h>
 | |
| +#include <linux/i2c.h>
 | |
| +#include <linux/mfd/core.h>
 | |
| +#include <linux/mfd/rn5t567.h>
 | |
| +#include <linux/regmap.h>
 | |
| +
 | |
| +static const struct mfd_cell rn5t567_cells[] = {
 | |
| +	{ .name = "rn5t567-regulator" },
 | |
| +	/*{ .name = "rn5t567-wdt" },
 | |
| +	  { .name = "rn5t567-pinctrl" },
 | |
| +	  { .name = "rn5t567-pm" }, */
 | |
| +};
 | |
| +
 | |
| +static bool rn5t567_reg_hole(unsigned int reg)
 | |
| +{
 | |
| +#define RN5T567_REG_SINGLE_HOLE_NUM 10
 | |
| +	unsigned char single_hole[RN5T567_REG_SINGLE_HOLE_NUM] = {
 | |
| +		0x4, 0x8, 0x1a, 0x29, 0x2b,
 | |
| +		0x34, 0x35, 0x3a, 0x3f, 0x43};
 | |
| +	int i;
 | |
| +
 | |
| +	for (i = 0; i < RN5T567_REG_SINGLE_HOLE_NUM; i++)
 | |
| +		if ((unsigned char)reg == single_hole[i])
 | |
| +			return true;
 | |
| +	if (reg > RN5T567_LDO5_SLOT && reg < RN5T567_PSO0_SLOT)
 | |
| +		return true;
 | |
| +	if (reg > RN5T567_LDODIS && reg < RN5T567_LDO1DAC)
 | |
| +		return true;
 | |
| +	if (reg > RN5T567_LDO5DAC && reg < RN5T567_LDORTCDAC)
 | |
| +		return true;
 | |
| +	if (reg > RN5T567_LDO5DAC_SLP && reg < RN5T567_IOSEL)
 | |
| +		return true;
 | |
| +	if (reg > RN5T567_GPLED_FUNC && reg < RN5T567_INTPOL)
 | |
| +		return true;
 | |
| +	if (reg > RN5T567_INTMON && reg < RN5T567_PREVINDAC)
 | |
| +		return true;
 | |
| +	if (reg > RN5T567_PREVINDAC && reg < RN5T567_DIESET)
 | |
| +		return true;
 | |
| +	if (reg > RN5T567_MAX_REG)
 | |
| +		return true;
 | |
| +#undef RN5T567_REG_SINGLE_HOLE_NUM
 | |
| +	return false;
 | |
| +}
 | |
| +
 | |
| +static bool rn5t567_opable_reg(struct device *dev, unsigned int reg)
 | |
| +{
 | |
| +	return !rn5t567_reg_hole(reg);
 | |
| +}
 | |
| +
 | |
| +static bool rn5t567_volatile_reg(struct device *dev, unsigned int reg)
 | |
| +{
 | |
| +	switch (reg) {
 | |
| +	case RN5T567_WATCHDOGCNT:
 | |
| +	case RN5T567_DCIRQ:
 | |
| +	case RN5T567_IR_GPR:
 | |
| +	case RN5T567_IR_GPF:
 | |
| +	case RN5T567_MON_IOIN:
 | |
| +	case RN5T567_INTMON:
 | |
| +		return true;
 | |
| +	default:
 | |
| +		return false;
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static struct reg_default rn5t567_reg_default[RN5T567_REG_NUM];
 | |
| +static const struct regmap_config rn5t567_regmap_config = {
 | |
| +	.reg_bits	= 8,
 | |
| +	.val_bits	= 8,
 | |
| +	.volatile_reg	= rn5t567_volatile_reg,
 | |
| +	.writeable_reg  = rn5t567_opable_reg,
 | |
| +	.readable_reg	= rn5t567_opable_reg,
 | |
| +	.max_register	= RN5T567_MAX_REG,
 | |
| +	.reg_defaults	= rn5t567_reg_default,
 | |
| +	.num_reg_defaults = ARRAY_SIZE(rn5t567_reg_default),
 | |
| +	.cache_type	= REGCACHE_RBTREE,
 | |
| +};
 | |
| +
 | |
| +static int __rn57567_reg_read(struct i2c_client *i2c, u8 reg)
 | |
| +{
 | |
| +	return i2c_smbus_read_byte_data(i2c, reg);
 | |
| +}
 | |
| +
 | |
| +static void rn5t567_reg_default_init(struct i2c_client *i2c)
 | |
| +{
 | |
| +	unsigned int reg, def;
 | |
| +	int i;
 | |
| +
 | |
| +	for (i = 0, reg = 0; i < RN5T567_REG_NUM &&
 | |
| +			reg <= RN5T567_MAX_REG; reg++) {
 | |
| +		if (rn5t567_reg_hole(reg) ||
 | |
| +				rn5t567_volatile_reg(NULL, reg))
 | |
| +			continue;
 | |
| +		rn5t567_reg_default[i].reg = reg;
 | |
| +		def = __rn57567_reg_read(i2c, (u8)reg);
 | |
| +		if (def < 0) {
 | |
| +			dev_warn(&i2c->dev, "register %x read failed: %d\n", reg, def);
 | |
| +			rn5t567_reg_default[i++].def = 0;
 | |
| +		} else
 | |
| +			rn5t567_reg_default[i++].def = def;
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static int rn5t567_i2c_probe(struct i2c_client *i2c,
 | |
| +		const struct i2c_device_id *id)
 | |
| +{
 | |
| +	struct regmap *regmap = NULL;
 | |
| +	int ret;
 | |
| +
 | |
| +	rn5t567_reg_default_init(i2c);
 | |
| +
 | |
| +	regmap = devm_regmap_init_i2c(i2c, &rn5t567_regmap_config);
 | |
| +	if (IS_ERR(regmap)) {
 | |
| +		ret = PTR_ERR(regmap);
 | |
| +		dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
 | |
| +		return ret;
 | |
| +	}
 | |
| +	i2c_set_clientdata(i2c, regmap);
 | |
| +
 | |
| +	ret = rn5t567_irq_init(i2c, regmap);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	ret = mfd_add_devices(&i2c->dev, -1, rn5t567_cells,
 | |
| +			ARRAY_SIZE(rn5t567_cells), NULL, 0, NULL);
 | |
| +	if (ret) {
 | |
| +		dev_err(&i2c->dev, "failed to add sub-devices: %d\n", ret);
 | |
| +		goto out_irq_domain_remove;
 | |
| +	}
 | |
| +
 | |
| +	dev_info(&i2c->dev, "%s success\n", __func__);
 | |
| +	return 0;
 | |
| +
 | |
| +out_irq_domain_remove:
 | |
| +	rn5t567_irq_deinit();
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
| +static int rn5t567_i2c_remove(struct i2c_client *i2c)
 | |
| +{
 | |
| +	mfd_remove_devices(&i2c->dev);
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static const struct of_device_id rn5t567_of_match[] = {
 | |
| +	{ .compatible = "ricoh,rn5t567" },
 | |
| +	{ }
 | |
| +};
 | |
| +MODULE_DEVICE_TABLE(of, rn5t567_of_match);
 | |
| +
 | |
| +static const struct i2c_device_id rc5t567_i2c_id[] = {
 | |
| +	{.name = "rc5t567", .driver_data = 0},
 | |
| +	{}
 | |
| +};
 | |
| +
 | |
| +
 | |
| +static struct i2c_driver rn5t567_i2c_driver = {
 | |
| +	.driver = {
 | |
| +		.name = "rn5t567",
 | |
| +		.of_match_table = of_match_ptr(rn5t567_of_match),
 | |
| +	},
 | |
| +	.probe = rn5t567_i2c_probe,
 | |
| +	.remove = rn5t567_i2c_remove,
 | |
| +	.id_table = rc5t567_i2c_id,
 | |
| +};
 | |
| +
 | |
| +static int __init rn5t567_i2c_init(void)
 | |
| +{
 | |
| +	int ret = -ENODEV;
 | |
| +
 | |
| +	ret = i2c_add_driver(&rn5t567_i2c_driver);
 | |
| +	if (ret != 0)
 | |
| +		pr_err("Failed to register I2C driver: %d\n", ret);
 | |
| +	return ret;
 | |
| +}
 | |
| +subsys_initcall(rn5t567_i2c_init);
 | |
| +
 | |
| +static void __exit rn5t567_i2c_exit(void)
 | |
| +{
 | |
| +	i2c_del_driver(&rn5t567_i2c_driver);
 | |
| +}
 | |
| +
 | |
| +module_exit(rn5t567_i2c_exit);
 | |
| +
 | |
| +MODULE_AUTHOR("cli <chen.li@ingenic.com>");
 | |
| +MODULE_DESCRIPTION("Ricoh RN5T567 MFD driver");
 | |
| +MODULE_LICENSE("GPL v2");
 |