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