brintos

brintos / linux-shallow public Read only

0
0
Text · 4.6 KiB · fd000a2 Raw
209 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * I2C access for DA9052 PMICs.4 *5 * Copyright(c) 2011 Dialog Semiconductor Ltd.6 *7 * Author: David Dajun Chen <dchen@diasemi.com>8 */9 10#include <linux/device.h>11#include <linux/module.h>12#include <linux/input.h>13#include <linux/mfd/core.h>14#include <linux/i2c.h>15#include <linux/err.h>16#include <linux/of.h>17 18#include <linux/mfd/da9052/da9052.h>19#include <linux/mfd/da9052/reg.h>20 21 22/* I2C safe register check */23static inline bool i2c_safe_reg(unsigned char reg)24{25	switch (reg) {26	case DA9052_STATUS_A_REG:27	case DA9052_STATUS_B_REG:28	case DA9052_STATUS_C_REG:29	case DA9052_STATUS_D_REG:30	case DA9052_ADC_RES_L_REG:31	case DA9052_ADC_RES_H_REG:32	case DA9052_VDD_RES_REG:33	case DA9052_ICHG_AV_REG:34	case DA9052_TBAT_RES_REG:35	case DA9052_ADCIN4_RES_REG:36	case DA9052_ADCIN5_RES_REG:37	case DA9052_ADCIN6_RES_REG:38	case DA9052_TJUNC_RES_REG:39	case DA9052_TSI_X_MSB_REG:40	case DA9052_TSI_Y_MSB_REG:41	case DA9052_TSI_LSB_REG:42	case DA9052_TSI_Z_MSB_REG:43		return true;44	default:45		return false;46	}47}48 49/*50 * There is an issue with DA9052 and DA9053_AA/BA/BB PMIC where the PMIC51 * gets lockup up or fails to respond following a system reset.52 * This fix is to follow any read or write with a dummy read to a safe53 * register.54 */55static int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)56{57	int val;58 59	switch (da9052->chip_id) {60	case DA9052:61	case DA9053_AA:62	case DA9053_BA:63	case DA9053_BB:64		/* A dummy read to a safe register address. */65		if (!i2c_safe_reg(reg))66			return regmap_read(da9052->regmap,67					   DA9052_PARK_REGISTER,68					   &val);69		break;70	case DA9053_BC:71	default:72		/*73		 * For other chips parking of I2C register74		 * to a safe place is not required.75		 */76		break;77	}78 79	return 0;80}81 82/*83 * According to errata item 24, multiwrite mode should be avoided84 * in order to prevent register data corruption after power-down.85 */86static int da9052_i2c_disable_multiwrite(struct da9052 *da9052)87{88	int reg_val, ret;89 90	ret = regmap_read(da9052->regmap, DA9052_CONTROL_B_REG, &reg_val);91	if (ret < 0)92		return ret;93 94	if (!(reg_val & DA9052_CONTROL_B_WRITEMODE)) {95		reg_val |= DA9052_CONTROL_B_WRITEMODE;96		ret = regmap_write(da9052->regmap, DA9052_CONTROL_B_REG,97				   reg_val);98		if (ret < 0)99			return ret;100	}101 102	return 0;103}104 105static const struct i2c_device_id da9052_i2c_id[] = {106	{"da9052", DA9052},107	{"da9053-aa", DA9053_AA},108	{"da9053-ba", DA9053_BA},109	{"da9053-bb", DA9053_BB},110	{"da9053-bc", DA9053_BC},111	{}112};113MODULE_DEVICE_TABLE(i2c, da9052_i2c_id);114 115#ifdef CONFIG_OF116static const struct of_device_id dialog_dt_ids[] = {117	{ .compatible = "dlg,da9052", .data = &da9052_i2c_id[0] },118	{ .compatible = "dlg,da9053-aa", .data = &da9052_i2c_id[1] },119	{ .compatible = "dlg,da9053-ba", .data = &da9052_i2c_id[2] },120	{ .compatible = "dlg,da9053-bb", .data = &da9052_i2c_id[3] },121	{ .compatible = "dlg,da9053-bc", .data = &da9052_i2c_id[4] },122	{ /* sentinel */ }123};124#endif125 126static int da9052_i2c_probe(struct i2c_client *client)127{128	const struct i2c_device_id *id = i2c_client_get_device_id(client);129	struct da9052 *da9052;130	int ret;131 132	da9052 = devm_kzalloc(&client->dev, sizeof(struct da9052), GFP_KERNEL);133	if (!da9052)134		return -ENOMEM;135 136	da9052->dev = &client->dev;137	da9052->chip_irq = client->irq;138	da9052->fix_io = da9052_i2c_fix;139 140	i2c_set_clientdata(client, da9052);141 142	da9052->regmap = devm_regmap_init_i2c(client, &da9052_regmap_config);143	if (IS_ERR(da9052->regmap)) {144		ret = PTR_ERR(da9052->regmap);145		dev_err(&client->dev, "Failed to allocate register map: %d\n",146			ret);147		return ret;148	}149 150	ret = da9052_i2c_disable_multiwrite(da9052);151	if (ret < 0)152		return ret;153 154#ifdef CONFIG_OF155	if (!id)156		id = of_device_get_match_data(&client->dev);157#endif158 159	if (!id) {160		ret = -ENODEV;161		dev_err(&client->dev, "id is null.\n");162		return ret;163	}164 165	return da9052_device_init(da9052, id->driver_data);166}167 168static void da9052_i2c_remove(struct i2c_client *client)169{170	struct da9052 *da9052 = i2c_get_clientdata(client);171 172	da9052_device_exit(da9052);173}174 175static struct i2c_driver da9052_i2c_driver = {176	.probe = da9052_i2c_probe,177	.remove = da9052_i2c_remove,178	.id_table = da9052_i2c_id,179	.driver = {180		.name = "da9052",181#ifdef CONFIG_OF182		.of_match_table = dialog_dt_ids,183#endif184	},185};186 187static int __init da9052_i2c_init(void)188{189	int ret;190 191	ret = i2c_add_driver(&da9052_i2c_driver);192	if (ret != 0) {193		pr_err("DA9052 I2C registration failed %d\n", ret);194		return ret;195	}196 197	return 0;198}199subsys_initcall(da9052_i2c_init);200 201static void __exit da9052_i2c_exit(void)202{203	i2c_del_driver(&da9052_i2c_driver);204}205module_exit(da9052_i2c_exit);206 207MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");208MODULE_DESCRIPTION("I2C driver for Dialog DA9052 PMIC");209