brintos

brintos / linux-shallow public Read only

0
0
Text · 9.2 KiB · cba64f1 Raw
380 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * I2C driver for Renesas Synchronization Management Unit (SMU) devices.4 *5 * Copyright (C) 2021 Integrated Device Technology, Inc., a Renesas Company.6 */7 8#include <linux/i2c.h>9#include <linux/init.h>10#include <linux/kernel.h>11#include <linux/mfd/core.h>12#include <linux/mfd/rsmu.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/regmap.h>16#include <linux/slab.h>17 18#include "rsmu.h"19 20/*21 * 32-bit register address: the lower 8 bits of the register address come22 * from the offset addr byte and the upper 24 bits come from the page register.23 */24#define	RSMU_CM_PAGE_ADDR		0xFC25#define RSMU_CM_PAGE_MASK		0xFFFFFF0026#define RSMU_CM_ADDRESS_MASK		0x000000FF27 28/*29 * 15-bit register address: the lower 7 bits of the register address come30 * from the offset addr byte and the upper 8 bits come from the page register.31 */32#define	RSMU_SABRE_PAGE_ADDR		0x7F33#define	RSMU_SABRE_PAGE_WINDOW		12834 35typedef int (*rsmu_rw_device)(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u8 bytes);36 37static const struct regmap_range_cfg rsmu_sabre_range_cfg[] = {38	{39		.range_min = 0,40		.range_max = 0x400,41		.selector_reg = RSMU_SABRE_PAGE_ADDR,42		.selector_mask = 0xFF,43		.selector_shift = 0,44		.window_start = 0,45		.window_len = RSMU_SABRE_PAGE_WINDOW,46	}47};48 49static bool rsmu_sabre_volatile_reg(struct device *dev, unsigned int reg)50{51	switch (reg) {52	case RSMU_SABRE_PAGE_ADDR:53		return false;54	default:55		return true;56	}57}58 59static int rsmu_smbus_i2c_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u8 bytes)60{61	struct i2c_client *client = to_i2c_client(rsmu->dev);62 63	return i2c_smbus_write_i2c_block_data(client, reg, bytes, buf);64}65 66static int rsmu_smbus_i2c_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u8 bytes)67{68	struct i2c_client *client = to_i2c_client(rsmu->dev);69	int ret;70 71	ret = i2c_smbus_read_i2c_block_data(client, reg, bytes, buf);72	if (ret == bytes)73		return 0;74	else if (ret < 0)75		return ret;76	else77		return -EIO;78}79 80static int rsmu_i2c_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u8 bytes)81{82	struct i2c_client *client = to_i2c_client(rsmu->dev);83	struct i2c_msg msg[2];84	int cnt;85 86	msg[0].addr = client->addr;87	msg[0].flags = 0;88	msg[0].len = 1;89	msg[0].buf = &reg;90 91	msg[1].addr = client->addr;92	msg[1].flags = I2C_M_RD;93	msg[1].len = bytes;94	msg[1].buf = buf;95 96	cnt = i2c_transfer(client->adapter, msg, 2);97 98	if (cnt < 0) {99		dev_err(rsmu->dev, "i2c_transfer failed at addr: %04x!", reg);100		return cnt;101	} else if (cnt != 2) {102		dev_err(rsmu->dev,103			"i2c_transfer sent only %d of 2 messages", cnt);104		return -EIO;105	}106 107	return 0;108}109 110static int rsmu_i2c_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u8 bytes)111{112	struct i2c_client *client = to_i2c_client(rsmu->dev);113	/* we add 1 byte for device register */114	u8 msg[RSMU_MAX_WRITE_COUNT + 1];115	int cnt;116 117	if (bytes > RSMU_MAX_WRITE_COUNT)118		return -EINVAL;119 120	msg[0] = reg;121	memcpy(&msg[1], buf, bytes);122 123	cnt = i2c_master_send(client, msg, bytes + 1);124 125	if (cnt < 0) {126		dev_err(&client->dev,127			"i2c_master_send failed at addr: %04x!", reg);128		return cnt;129	}130 131	return 0;132}133 134static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u32 reg,135				    rsmu_rw_device rsmu_write_device)136{137	u32 page = reg & RSMU_CM_PAGE_MASK;138	u8 buf[4];139	int err;140 141	/* Do not modify offset register for none-scsr registers */142	if (reg < RSMU_CM_SCSR_BASE)143		return 0;144 145	/* Simply return if we are on the same page */146	if (rsmu->page == page)147		return 0;148 149	buf[0] = 0x0;150	buf[1] = (u8)((page >> 8) & 0xFF);151	buf[2] = (u8)((page >> 16) & 0xFF);152	buf[3] = (u8)((page >> 24) & 0xFF);153 154	err = rsmu_write_device(rsmu, RSMU_CM_PAGE_ADDR, buf, sizeof(buf));155	if (err)156		dev_err(rsmu->dev, "Failed to set page offset 0x%x\n", page);157	else158		/* Remember the last page */159		rsmu->page = page;160 161	return err;162}163 164static int rsmu_i2c_reg_read(void *context, unsigned int reg, unsigned int *val)165{166	struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context);167	u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK);168	int err;169 170	err = rsmu_write_page_register(rsmu, reg, rsmu_i2c_write_device);171	if (err)172		return err;173 174	err = rsmu_i2c_read_device(rsmu, addr, (u8 *)val, 1);175	if (err)176		dev_err(rsmu->dev, "Failed to read offset address 0x%x\n", addr);177 178	return err;179}180 181static int rsmu_i2c_reg_write(void *context, unsigned int reg, unsigned int val)182{183	struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context);184	u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK);185	u8 data = (u8)val;186	int err;187 188	err = rsmu_write_page_register(rsmu, reg, rsmu_i2c_write_device);189	if (err)190		return err;191 192	err = rsmu_i2c_write_device(rsmu, addr, &data, 1);193	if (err)194		dev_err(rsmu->dev,195			"Failed to write offset address 0x%x\n", addr);196 197	return err;198}199 200static int rsmu_smbus_i2c_reg_read(void *context, unsigned int reg, unsigned int *val)201{202	struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context);203	u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK);204	int err;205 206	err = rsmu_write_page_register(rsmu, reg, rsmu_smbus_i2c_write_device);207	if (err)208		return err;209 210	err = rsmu_smbus_i2c_read_device(rsmu, addr, (u8 *)val, 1);211	if (err)212		dev_err(rsmu->dev, "Failed to read offset address 0x%x\n", addr);213 214	return err;215}216 217static int rsmu_smbus_i2c_reg_write(void *context, unsigned int reg, unsigned int val)218{219	struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context);220	u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK);221	u8 data = (u8)val;222	int err;223 224	err = rsmu_write_page_register(rsmu, reg, rsmu_smbus_i2c_write_device);225	if (err)226		return err;227 228	err = rsmu_smbus_i2c_write_device(rsmu, addr, &data, 1);229	if (err)230		dev_err(rsmu->dev,231			"Failed to write offset address 0x%x\n", addr);232 233	return err;234}235 236static const struct regmap_config rsmu_i2c_cm_regmap_config = {237	.reg_bits = 32,238	.val_bits = 8,239	.max_register = 0x20120000,240	.reg_read = rsmu_i2c_reg_read,241	.reg_write = rsmu_i2c_reg_write,242	.cache_type = REGCACHE_NONE,243};244 245static const struct regmap_config rsmu_smbus_i2c_cm_regmap_config = {246	.reg_bits = 32,247	.val_bits = 8,248	.max_register = 0x20120000,249	.reg_read = rsmu_smbus_i2c_reg_read,250	.reg_write = rsmu_smbus_i2c_reg_write,251	.cache_type = REGCACHE_NONE,252};253 254static const struct regmap_config rsmu_sabre_regmap_config = {255	.reg_bits = 8,256	.val_bits = 8,257	.max_register = 0x400,258	.ranges = rsmu_sabre_range_cfg,259	.num_ranges = ARRAY_SIZE(rsmu_sabre_range_cfg),260	.volatile_reg = rsmu_sabre_volatile_reg,261	.cache_type = REGCACHE_MAPLE,262	.can_multi_write = true,263};264 265static const struct regmap_config rsmu_sl_regmap_config = {266	.reg_bits = 16,267	.val_bits = 8,268	.reg_format_endian = REGMAP_ENDIAN_BIG,269	.max_register = 0x340,270	.cache_type = REGCACHE_NONE,271	.can_multi_write = true,272};273 274static int rsmu_i2c_probe(struct i2c_client *client)275{276	const struct i2c_device_id *id = i2c_client_get_device_id(client);277	const struct regmap_config *cfg;278	struct rsmu_ddata *rsmu;279	int ret;280 281	rsmu = devm_kzalloc(&client->dev, sizeof(*rsmu), GFP_KERNEL);282	if (!rsmu)283		return -ENOMEM;284 285	i2c_set_clientdata(client, rsmu);286 287	rsmu->dev = &client->dev;288	rsmu->type = (enum rsmu_type)id->driver_data;289 290	switch (rsmu->type) {291	case RSMU_CM:292		if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {293			cfg = &rsmu_i2c_cm_regmap_config;294		} else if (i2c_check_functionality(client->adapter,295						   I2C_FUNC_SMBUS_I2C_BLOCK)) {296			cfg = &rsmu_smbus_i2c_cm_regmap_config;297		} else {298			dev_err(rsmu->dev, "Unsupported i2c adapter\n");299			return -ENOTSUPP;300		}301		break;302	case RSMU_SABRE:303		cfg = &rsmu_sabre_regmap_config;304		break;305	case RSMU_SL:306		cfg = &rsmu_sl_regmap_config;307		break;308	default:309		dev_err(rsmu->dev, "Unsupported RSMU device type: %d\n", rsmu->type);310		return -ENODEV;311	}312 313	if (rsmu->type == RSMU_CM)314		rsmu->regmap = devm_regmap_init(&client->dev, NULL, client, cfg);315	else316		rsmu->regmap = devm_regmap_init_i2c(client, cfg);317 318	if (IS_ERR(rsmu->regmap)) {319		ret = PTR_ERR(rsmu->regmap);320		dev_err(rsmu->dev, "Failed to allocate register map: %d\n", ret);321		return ret;322	}323 324	return rsmu_core_init(rsmu);325}326 327static void rsmu_i2c_remove(struct i2c_client *client)328{329	struct rsmu_ddata *rsmu = i2c_get_clientdata(client);330 331	rsmu_core_exit(rsmu);332}333 334static const struct i2c_device_id rsmu_i2c_id[] = {335	{ "8a34000",  RSMU_CM },336	{ "8a34001",  RSMU_CM },337	{ "82p33810", RSMU_SABRE },338	{ "82p33811", RSMU_SABRE },339	{ "8v19n850", RSMU_SL },340	{ "8v19n851", RSMU_SL },341	{}342};343MODULE_DEVICE_TABLE(i2c, rsmu_i2c_id);344 345static const struct of_device_id rsmu_i2c_of_match[] = {346	{ .compatible = "idt,8a34000",  .data = (void *)RSMU_CM },347	{ .compatible = "idt,8a34001",  .data = (void *)RSMU_CM },348	{ .compatible = "idt,82p33810", .data = (void *)RSMU_SABRE },349	{ .compatible = "idt,82p33811", .data = (void *)RSMU_SABRE },350	{ .compatible = "idt,8v19n850", .data = (void *)RSMU_SL },351	{ .compatible = "idt,8v19n851", .data = (void *)RSMU_SL },352	{}353};354MODULE_DEVICE_TABLE(of, rsmu_i2c_of_match);355 356static struct i2c_driver rsmu_i2c_driver = {357	.driver = {358		.name = "rsmu-i2c",359		.of_match_table = rsmu_i2c_of_match,360	},361	.probe = rsmu_i2c_probe,362	.remove	= rsmu_i2c_remove,363	.id_table = rsmu_i2c_id,364};365 366static int __init rsmu_i2c_init(void)367{368	return i2c_add_driver(&rsmu_i2c_driver);369}370subsys_initcall(rsmu_i2c_init);371 372static void __exit rsmu_i2c_exit(void)373{374	i2c_del_driver(&rsmu_i2c_driver);375}376module_exit(rsmu_i2c_exit);377 378MODULE_DESCRIPTION("Renesas SMU I2C driver");379MODULE_LICENSE("GPL");380