brintos

brintos / linux-shallow public Read only

0
0
Text · 6.8 KiB · 0ea7d77 Raw
296 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * w1_ds2430.c - w1 family 14 (DS2430) driver4 **5 * Copyright (c) 2019 Angelo Dureghello <angelo.dureghello@timesys.com>6 *7 * Cloned and modified from ds24318 * Copyright (c) 2008 Bernhard Weirich <bernhard.weirich@riedel.net>9 *10 */11 12#include <linux/kernel.h>13#include <linux/module.h>14#include <linux/moduleparam.h>15#include <linux/device.h>16#include <linux/types.h>17#include <linux/delay.h>18 19#include <linux/w1.h>20 21#define W1_EEPROM_DS2430	0x1422 23#define W1_F14_EEPROM_SIZE	3224#define W1_F14_PAGE_COUNT	125#define W1_F14_PAGE_BITS	526#define W1_F14_PAGE_SIZE	(1 << W1_F14_PAGE_BITS)27#define W1_F14_PAGE_MASK	0x1F28 29#define W1_F14_SCRATCH_BITS	530#define W1_F14_SCRATCH_SIZE	(1 << W1_F14_SCRATCH_BITS)31#define W1_F14_SCRATCH_MASK	(W1_F14_SCRATCH_SIZE-1)32 33#define W1_F14_READ_EEPROM	0xF034#define W1_F14_WRITE_SCRATCH	0x0F35#define W1_F14_READ_SCRATCH	0xAA36#define W1_F14_COPY_SCRATCH	0x5537#define W1_F14_VALIDATION_KEY	0xa538 39#define W1_F14_TPROG_MS		1140#define W1_F14_READ_RETRIES	1041#define W1_F14_READ_MAXLEN	W1_F14_SCRATCH_SIZE42 43/*44 * Check the file size bounds and adjusts count as needed.45 * This would not be needed if the file size didn't reset to 0 after a write.46 */47static inline size_t w1_f14_fix_count(loff_t off, size_t count, size_t size)48{49	if (off > size)50		return 0;51 52	if ((off + count) > size)53		return size - off;54 55	return count;56}57 58/*59 * Read a block from W1 ROM two times and compares the results.60 * If they are equal they are returned, otherwise the read61 * is repeated W1_F14_READ_RETRIES times.62 *63 * count must not exceed W1_F14_READ_MAXLEN.64 */65static int w1_f14_readblock(struct w1_slave *sl, int off, int count, char *buf)66{67	u8 wrbuf[2];68	u8 cmp[W1_F14_READ_MAXLEN];69	int tries = W1_F14_READ_RETRIES;70 71	do {72		wrbuf[0] = W1_F14_READ_EEPROM;73		wrbuf[1] = off & 0xff;74 75		if (w1_reset_select_slave(sl))76			return -1;77 78		w1_write_block(sl->master, wrbuf, 2);79		w1_read_block(sl->master, buf, count);80 81		if (w1_reset_select_slave(sl))82			return -1;83 84		w1_write_block(sl->master, wrbuf, 2);85		w1_read_block(sl->master, cmp, count);86 87		if (!memcmp(cmp, buf, count))88			return 0;89	} while (--tries);90 91	dev_err(&sl->dev, "proof reading failed %d times\n",92			W1_F14_READ_RETRIES);93 94	return -1;95}96 97static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,98			   struct bin_attribute *bin_attr, char *buf,99			   loff_t off, size_t count)100{101	struct w1_slave *sl = kobj_to_w1_slave(kobj);102	int todo = count;103 104	count = w1_f14_fix_count(off, count, W1_F14_EEPROM_SIZE);105	if (count == 0)106		return 0;107 108	mutex_lock(&sl->master->bus_mutex);109 110	/* read directly from the EEPROM in chunks of W1_F14_READ_MAXLEN */111	while (todo > 0) {112		int block_read;113 114		if (todo >= W1_F14_READ_MAXLEN)115			block_read = W1_F14_READ_MAXLEN;116		else117			block_read = todo;118 119		if (w1_f14_readblock(sl, off, block_read, buf) < 0)120			count = -EIO;121 122		todo -= W1_F14_READ_MAXLEN;123		buf += W1_F14_READ_MAXLEN;124		off += W1_F14_READ_MAXLEN;125	}126 127	mutex_unlock(&sl->master->bus_mutex);128 129	return count;130}131 132/*133 * Writes to the scratchpad and reads it back for verification.134 * Then copies the scratchpad to EEPROM.135 * The data must be aligned at W1_F14_SCRATCH_SIZE bytes and136 * must be W1_F14_SCRATCH_SIZE bytes long.137 * The master must be locked.138 *139 * @param sl	The slave structure140 * @param addr	Address for the write141 * @param len   length must be <= (W1_F14_PAGE_SIZE - (addr & W1_F14_PAGE_MASK))142 * @param data	The data to write143 * @return	0=Success -1=failure144 */145static int w1_f14_write(struct w1_slave *sl, int addr, int len, const u8 *data)146{147	int tries = W1_F14_READ_RETRIES;148	u8 wrbuf[2];149	u8 rdbuf[W1_F14_SCRATCH_SIZE + 3];150 151retry:152 153	/* Write the data to the scratchpad */154	if (w1_reset_select_slave(sl))155		return -1;156 157	wrbuf[0] = W1_F14_WRITE_SCRATCH;158	wrbuf[1] = addr & 0xff;159 160	w1_write_block(sl->master, wrbuf, 2);161	w1_write_block(sl->master, data, len);162 163	/* Read the scratchpad and verify */164	if (w1_reset_select_slave(sl))165		return -1;166 167	w1_write_8(sl->master, W1_F14_READ_SCRATCH);168	w1_read_block(sl->master, rdbuf, len + 2);169 170	/*171	 * Compare what was read against the data written172	 * Note: on read scratchpad, device returns 2 bulk 0xff bytes,173	 * to be discarded.174	 */175	if ((memcmp(data, &rdbuf[2], len) != 0)) {176 177		if (--tries)178			goto retry;179 180		dev_err(&sl->dev,181			"could not write to eeprom, scratchpad compare failed %d times\n",182			W1_F14_READ_RETRIES);183 184		return -1;185	}186 187	/* Copy the scratchpad to EEPROM */188	if (w1_reset_select_slave(sl))189		return -1;190 191	wrbuf[0] = W1_F14_COPY_SCRATCH;192	wrbuf[1] = W1_F14_VALIDATION_KEY;193	w1_write_block(sl->master, wrbuf, 2);194 195	/* Sleep for tprog ms to wait for the write to complete */196	msleep(W1_F14_TPROG_MS);197 198	/* Reset the bus to wake up the EEPROM  */199	w1_reset_bus(sl->master);200 201	return 0;202}203 204static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,205			    struct bin_attribute *bin_attr, char *buf,206			    loff_t off, size_t count)207{208	struct w1_slave *sl = kobj_to_w1_slave(kobj);209	int addr, len;210	int copy;211 212	count = w1_f14_fix_count(off, count, W1_F14_EEPROM_SIZE);213	if (count == 0)214		return 0;215 216	mutex_lock(&sl->master->bus_mutex);217 218	/* Can only write data in blocks of the size of the scratchpad */219	addr = off;220	len = count;221	while (len > 0) {222 223		/* if len too short or addr not aligned */224		if (len < W1_F14_SCRATCH_SIZE || addr & W1_F14_SCRATCH_MASK) {225			char tmp[W1_F14_SCRATCH_SIZE];226 227			/* read the block and update the parts to be written */228			if (w1_f14_readblock(sl, addr & ~W1_F14_SCRATCH_MASK,229					W1_F14_SCRATCH_SIZE, tmp)) {230				count = -EIO;231				goto out_up;232			}233 234			/* copy at most to the boundary of the PAGE or len */235			copy = W1_F14_SCRATCH_SIZE -236				(addr & W1_F14_SCRATCH_MASK);237 238			if (copy > len)239				copy = len;240 241			memcpy(&tmp[addr & W1_F14_SCRATCH_MASK], buf, copy);242			if (w1_f14_write(sl, addr & ~W1_F14_SCRATCH_MASK,243					W1_F14_SCRATCH_SIZE, tmp) < 0) {244				count = -EIO;245				goto out_up;246			}247		} else {248 249			copy = W1_F14_SCRATCH_SIZE;250			if (w1_f14_write(sl, addr, copy, buf) < 0) {251				count = -EIO;252				goto out_up;253			}254		}255		buf += copy;256		addr += copy;257		len -= copy;258	}259 260out_up:261	mutex_unlock(&sl->master->bus_mutex);262 263	return count;264}265 266static BIN_ATTR_RW(eeprom, W1_F14_EEPROM_SIZE);267 268static struct bin_attribute *w1_f14_bin_attrs[] = {269	&bin_attr_eeprom,270	NULL,271};272 273static const struct attribute_group w1_f14_group = {274	.bin_attrs = w1_f14_bin_attrs,275};276 277static const struct attribute_group *w1_f14_groups[] = {278	&w1_f14_group,279	NULL,280};281 282static const struct w1_family_ops w1_f14_fops = {283	.groups	= w1_f14_groups,284};285 286static struct w1_family w1_family_14 = {287	.fid = W1_EEPROM_DS2430,288	.fops = &w1_f14_fops,289};290module_w1_family(w1_family_14);291 292MODULE_AUTHOR("Angelo Dureghello <angelo.dureghello@timesys.com>");293MODULE_DESCRIPTION("w1 family 14 driver for DS2430, 256b EEPROM");294MODULE_LICENSE("GPL");295MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS2430));296