brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · cb426f7 Raw
292 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * w1_ds250x.c - w1 family 09/0b/89/91 (DS250x) driver4 */5 6#include <linux/kernel.h>7#include <linux/module.h>8#include <linux/moduleparam.h>9#include <linux/device.h>10#include <linux/types.h>11#include <linux/delay.h>12#include <linux/slab.h>13#include <linux/crc16.h>14 15#include <linux/w1.h>16#include <linux/nvmem-provider.h>17 18#define W1_DS2501_UNW_FAMILY    0x9119#define W1_DS2501_SIZE          6420 21#define W1_DS2502_FAMILY        0x0922#define W1_DS2502_UNW_FAMILY    0x8923#define W1_DS2502_SIZE          12824 25#define W1_DS2505_FAMILY	0x0b26#define W1_DS2505_SIZE		204827 28#define W1_PAGE_SIZE		3229 30#define W1_EXT_READ_MEMORY	0xA531#define W1_READ_DATA_CRC        0xC332 33#define OFF2PG(off)	((off) / W1_PAGE_SIZE)34 35#define CRC16_INIT		036#define CRC16_VALID		0xb00137 38struct w1_eprom_data {39	size_t size;40	int (*read)(struct w1_slave *sl, int pageno);41	u8 eprom[W1_DS2505_SIZE];42	DECLARE_BITMAP(page_present, W1_DS2505_SIZE / W1_PAGE_SIZE);43	char nvmem_name[64];44};45 46static int w1_ds2502_read_page(struct w1_slave *sl, int pageno)47{48	struct w1_eprom_data *data = sl->family_data;49	int pgoff = pageno * W1_PAGE_SIZE;50	int ret = -EIO;51	u8 buf[3];52	u8 crc8;53 54	if (test_bit(pageno, data->page_present))55		return 0; /* page already present */56 57	mutex_lock(&sl->master->bus_mutex);58 59	if (w1_reset_select_slave(sl))60		goto err;61 62	buf[0] = W1_READ_DATA_CRC;63	buf[1] = pgoff & 0xff;64	buf[2] = pgoff >> 8;65	w1_write_block(sl->master, buf, 3);66 67	crc8 = w1_read_8(sl->master);68	if (w1_calc_crc8(buf, 3) != crc8)69		goto err;70 71	w1_read_block(sl->master, &data->eprom[pgoff], W1_PAGE_SIZE);72 73	crc8 = w1_read_8(sl->master);74	if (w1_calc_crc8(&data->eprom[pgoff], W1_PAGE_SIZE) != crc8)75		goto err;76 77	set_bit(pageno, data->page_present); /* mark page present */78	ret = 0;79err:80	mutex_unlock(&sl->master->bus_mutex);81	return ret;82}83 84static int w1_ds2505_read_page(struct w1_slave *sl, int pageno)85{86	struct w1_eprom_data *data = sl->family_data;87	int redir_retries = 16;88	int pgoff, epoff;89	int ret = -EIO;90	u8 buf[6];91	u8 redir;92	u16 crc;93 94	if (test_bit(pageno, data->page_present))95		return 0; /* page already present */96 97	epoff = pgoff = pageno * W1_PAGE_SIZE;98	mutex_lock(&sl->master->bus_mutex);99 100retry:101	if (w1_reset_select_slave(sl))102		goto err;103 104	buf[0] = W1_EXT_READ_MEMORY;105	buf[1] = pgoff & 0xff;106	buf[2] = pgoff >> 8;107	w1_write_block(sl->master, buf, 3);108	w1_read_block(sl->master, buf + 3, 3); /* redir, crc16 */109	redir = buf[3];110	crc = crc16(CRC16_INIT, buf, 6);111 112	if (crc != CRC16_VALID)113		goto err;114 115 116	if (redir != 0xff) {117		redir_retries--;118		if (redir_retries < 0)119			goto err;120 121		pgoff = (redir ^ 0xff) * W1_PAGE_SIZE;122		goto retry;123	}124 125	w1_read_block(sl->master, &data->eprom[epoff], W1_PAGE_SIZE);126	w1_read_block(sl->master, buf, 2); /* crc16 */127	crc = crc16(CRC16_INIT, &data->eprom[epoff], W1_PAGE_SIZE);128	crc = crc16(crc, buf, 2);129 130	if (crc != CRC16_VALID)131		goto err;132 133	set_bit(pageno, data->page_present);134	ret = 0;135err:136	mutex_unlock(&sl->master->bus_mutex);137	return ret;138}139 140static int w1_nvmem_read(void *priv, unsigned int off, void *buf, size_t count)141{142	struct w1_slave *sl = priv;143	struct w1_eprom_data *data = sl->family_data;144	size_t eprom_size = data->size;145	int ret;146	int i;147 148	if (off > eprom_size)149		return -EINVAL;150 151	if ((off + count) > eprom_size)152		count = eprom_size - off;153 154	i = OFF2PG(off);155	do {156		ret = data->read(sl, i++);157		if (ret < 0)158			return ret;159	} while (i < OFF2PG(off + count));160 161	memcpy(buf, &data->eprom[off], count);162	return 0;163}164 165static int w1_eprom_add_slave(struct w1_slave *sl)166{167	struct w1_eprom_data *data;168	struct nvmem_device *nvmem;169	struct nvmem_config nvmem_cfg = {170		.dev = &sl->dev,171		.add_legacy_fixed_of_cells = true,172		.reg_read = w1_nvmem_read,173		.type = NVMEM_TYPE_OTP,174		.read_only = true,175		.word_size = 1,176		.priv = sl,177		.id = -1178	};179 180	data = devm_kzalloc(&sl->dev, sizeof(struct w1_eprom_data), GFP_KERNEL);181	if (!data)182		return -ENOMEM;183 184	sl->family_data = data;185	switch (sl->family->fid) {186	case W1_DS2501_UNW_FAMILY:187		data->size = W1_DS2501_SIZE;188		data->read = w1_ds2502_read_page;189		break;190	case W1_DS2502_FAMILY:191	case W1_DS2502_UNW_FAMILY:192		data->size = W1_DS2502_SIZE;193		data->read = w1_ds2502_read_page;194		break;195	case W1_DS2505_FAMILY:196		data->size = W1_DS2505_SIZE;197		data->read = w1_ds2505_read_page;198		break;199	}200 201	if (sl->master->bus_master->dev_id)202		snprintf(data->nvmem_name, sizeof(data->nvmem_name),203			 "%s-%02x-%012llx",204			 sl->master->bus_master->dev_id, sl->reg_num.family,205			 (unsigned long long)sl->reg_num.id);206	else207		snprintf(data->nvmem_name, sizeof(data->nvmem_name),208			 "%02x-%012llx",209			 sl->reg_num.family,210			 (unsigned long long)sl->reg_num.id);211 212	nvmem_cfg.name = data->nvmem_name;213	nvmem_cfg.size = data->size;214 215	nvmem = devm_nvmem_register(&sl->dev, &nvmem_cfg);216	return PTR_ERR_OR_ZERO(nvmem);217}218 219static const struct w1_family_ops w1_eprom_fops = {220	.add_slave	= w1_eprom_add_slave,221};222 223static struct w1_family w1_family_09 = {224	.fid = W1_DS2502_FAMILY,225	.fops = &w1_eprom_fops,226};227 228static struct w1_family w1_family_0b = {229	.fid = W1_DS2505_FAMILY,230	.fops = &w1_eprom_fops,231};232 233static struct w1_family w1_family_89 = {234	.fid = W1_DS2502_UNW_FAMILY,235	.fops = &w1_eprom_fops,236};237 238static struct w1_family w1_family_91 = {239	.fid = W1_DS2501_UNW_FAMILY,240	.fops = &w1_eprom_fops,241};242 243static int __init w1_ds250x_init(void)244{245	int err;246 247	err = w1_register_family(&w1_family_09);248	if (err)249		return err;250 251	err = w1_register_family(&w1_family_0b);252	if (err)253		goto err_0b;254 255	err = w1_register_family(&w1_family_89);256	if (err)257		goto err_89;258 259	err = w1_register_family(&w1_family_91);260	if (err)261		goto err_91;262 263	return 0;264 265err_91:266	w1_unregister_family(&w1_family_89);267err_89:268	w1_unregister_family(&w1_family_0b);269err_0b:270	w1_unregister_family(&w1_family_09);271	return err;272}273 274static void __exit w1_ds250x_exit(void)275{276	w1_unregister_family(&w1_family_09);277	w1_unregister_family(&w1_family_0b);278	w1_unregister_family(&w1_family_89);279	w1_unregister_family(&w1_family_91);280}281 282module_init(w1_ds250x_init);283module_exit(w1_ds250x_exit);284 285MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfe@suse.de>");286MODULE_DESCRIPTION("w1 family driver for DS250x Add Only Memory");287MODULE_LICENSE("GPL");288MODULE_ALIAS("w1-family-" __stringify(W1_DS2502_FAMILY));289MODULE_ALIAS("w1-family-" __stringify(W1_DS2505_FAMILY));290MODULE_ALIAS("w1-family-" __stringify(W1_DS2501_UNW_FAMILY));291MODULE_ALIAS("w1-family-" __stringify(W1_DS2502_UNW_FAMILY));292