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 + * + * Based on code + * drivers/mfd/rc5t583.c + * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. + * Author: Laxman dewangan + * + * 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 . + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 "); +MODULE_DESCRIPTION("Ricoh RN5T567 MFD driver"); +MODULE_LICENSE("GPL v2");