diff options
Diffstat (limited to 'drivers/w1/slaves/w1_ds2433.c')
| -rw-r--r-- | drivers/w1/slaves/w1_ds2433.c | 232 |
1 files changed, 164 insertions, 68 deletions
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c index 10cc1b6176e6..3371d804dc6c 100644 --- a/drivers/w1/slaves/w1_ds2433.c +++ b/drivers/w1/slaves/w1_ds2433.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * w1_ds2433.c - w1 family 23 (DS2433) driver + * w1_ds2433.c - w1 family 23 (DS2433) & 43 (DS28EC20) eeprom driver * * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com> - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. + * Copyright (c) 2023 Marc Ferland <marc.ferland@sonatest.com> */ #include <linux/kernel.h> @@ -22,34 +21,51 @@ #endif -#include "../w1.h" -#include "../w1_int.h" -#include "../w1_family.h" +#include <linux/w1.h> -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); -MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM"); -MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS2433)); +#define W1_EEPROM_DS2433 0x23 +#define W1_EEPROM_DS28EC20 0x43 + +#define W1_EEPROM_DS2433_SIZE 512 +#define W1_EEPROM_DS28EC20_SIZE 2560 -#define W1_EEPROM_SIZE 512 -#define W1_PAGE_COUNT 16 #define W1_PAGE_SIZE 32 #define W1_PAGE_BITS 5 #define W1_PAGE_MASK 0x1F - -#define W1_F23_TIME 300 +#define W1_VALIDCRC_MAX 96 #define W1_F23_READ_EEPROM 0xF0 #define W1_F23_WRITE_SCRATCH 0x0F #define W1_F23_READ_SCRATCH 0xAA #define W1_F23_COPY_SCRATCH 0x55 +struct ds2433_config { + size_t eeprom_size; /* eeprom size in bytes */ + unsigned int page_count; /* number of 256 bits pages */ + unsigned int tprog; /* time in ms for page programming */ +}; + +static const struct ds2433_config config_f23 = { + .eeprom_size = W1_EEPROM_DS2433_SIZE, + .page_count = 16, + .tprog = 5, +}; + +static const struct ds2433_config config_f43 = { + .eeprom_size = W1_EEPROM_DS28EC20_SIZE, + .page_count = 80, + .tprog = 10, +}; + struct w1_f23_data { - u8 memory[W1_EEPROM_SIZE]; - u32 validcrc; +#ifdef CONFIG_W1_SLAVE_DS2433_CRC + u8 *memory; + DECLARE_BITMAP(validcrc, W1_VALIDCRC_MAX); +#endif + const struct ds2433_config *cfg; }; -/** +/* * Check the file size bounds and adjusts count as needed. * This would not be needed if the file size didn't reset to 0 after a write. */ @@ -71,11 +87,11 @@ static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data, u8 wrbuf[3]; int off = block * W1_PAGE_SIZE; - if (data->validcrc & (1 << block)) + if (test_bit(block, data->validcrc)) return 0; if (w1_reset_select_slave(sl)) { - data->validcrc = 0; + bitmap_zero(data->validcrc, data->cfg->page_count); return -EIO; } @@ -87,15 +103,15 @@ static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data, /* cache the block if the CRC is valid */ if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID) - data->validcrc |= (1 << block); + set_bit(block, data->validcrc); return 0; } #endif /* CONFIG_W1_SLAVE_DS2433_CRC */ -static ssize_t w1_f23_read_bin(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, + const struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); #ifdef CONFIG_W1_SLAVE_DS2433_CRC @@ -105,7 +121,8 @@ static ssize_t w1_f23_read_bin(struct file *filp, struct kobject *kobj, u8 wrbuf[3]; #endif - if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) + count = w1_f23_fix_count(off, count, bin_attr->size); + if (!count) return 0; mutex_lock(&sl->master->bus_mutex); @@ -122,7 +139,7 @@ static ssize_t w1_f23_read_bin(struct file *filp, struct kobject *kobj, } memcpy(buf, &data->memory[off], count); -#else /* CONFIG_W1_SLAVE_DS2433_CRC */ +#else /* CONFIG_W1_SLAVE_DS2433_CRC */ /* read directly from the EEPROM */ if (w1_reset_select_slave(sl)) { @@ -145,22 +162,21 @@ out_up: } /** - * Writes to the scratchpad and reads it back for verification. + * w1_f23_write() - Writes to the scratchpad and reads it back for verification. + * @sl: The slave structure + * @addr: Address for the write + * @len: length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK)) + * @data: The data to write + * * Then copies the scratchpad to EEPROM. * The data must be on one page. * The master must be locked. * - * @param sl The slave structure - * @param addr Address for the write - * @param len length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK)) - * @param data The data to write - * @return 0=Success -1=failure + * Return: 0=Success, -1=failure */ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data) { -#ifdef CONFIG_W1_SLAVE_DS2433_CRC struct w1_f23_data *f23 = sl->family_data; -#endif u8 wrbuf[4]; u8 rdbuf[W1_PAGE_SIZE + 3]; u8 es = (addr + len - 1) & 0x1f; @@ -196,25 +212,26 @@ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data) wrbuf[3] = es; w1_write_block(sl->master, wrbuf, 4); - /* Sleep for 5 ms to wait for the write to complete */ - msleep(5); + /* Sleep for tprog ms to wait for the write to complete */ + msleep(f23->cfg->tprog); /* Reset the bus to wake up the EEPROM (this may not be needed) */ w1_reset_bus(sl->master); #ifdef CONFIG_W1_SLAVE_DS2433_CRC - f23->validcrc &= ~(1 << (addr >> W1_PAGE_BITS)); + clear_bit(addr >> W1_PAGE_BITS, f23->validcrc); #endif return 0; } -static ssize_t w1_f23_write_bin(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t eeprom_write(struct file *filp, struct kobject *kobj, + const struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { struct w1_slave *sl = kobj_to_w1_slave(kobj); int addr, len, idx; - if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) + count = w1_f23_fix_count(off, count, bin_attr->size); + if (!count) return 0; #ifdef CONFIG_W1_SLAVE_DS2433_CRC @@ -257,51 +274,103 @@ out_up: return count; } -static struct bin_attribute w1_f23_bin_attr = { - .attr = { - .name = "eeprom", - .mode = S_IRUGO | S_IWUSR, - }, - .size = W1_EEPROM_SIZE, - .read = w1_f23_read_bin, - .write = w1_f23_write_bin, +static const struct bin_attribute bin_attr_f23_eeprom = { + .attr = { .name = "eeprom", .mode = 0644 }, + .read = eeprom_read, + .write = eeprom_write, + .size = W1_EEPROM_DS2433_SIZE, +}; + +static const struct bin_attribute bin_attr_f43_eeprom = { + .attr = { .name = "eeprom", .mode = 0644 }, + .read = eeprom_read, + .write = eeprom_write, + .size = W1_EEPROM_DS28EC20_SIZE, +}; + +static const struct bin_attribute *const w1_f23_bin_attributes[] = { + &bin_attr_f23_eeprom, + NULL, +}; + +static const struct attribute_group w1_f23_group = { + .bin_attrs = w1_f23_bin_attributes, +}; + +static const struct attribute_group *w1_f23_groups[] = { + &w1_f23_group, + NULL, +}; + +static const struct bin_attribute *const w1_f43_bin_attributes[] = { + &bin_attr_f43_eeprom, + NULL, +}; + +static const struct attribute_group w1_f43_group = { + .bin_attrs = w1_f43_bin_attributes, +}; + +static const struct attribute_group *w1_f43_groups[] = { + &w1_f43_group, + NULL, }; static int w1_f23_add_slave(struct w1_slave *sl) { - int err; -#ifdef CONFIG_W1_SLAVE_DS2433_CRC struct w1_f23_data *data; data = kzalloc(sizeof(struct w1_f23_data), GFP_KERNEL); if (!data) return -ENOMEM; - sl->family_data = data; -#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ - - err = sysfs_create_bin_file(&sl->dev.kobj, &w1_f23_bin_attr); + switch (sl->family->fid) { + case W1_EEPROM_DS2433: + data->cfg = &config_f23; + break; + case W1_EEPROM_DS28EC20: + data->cfg = &config_f43; + break; + } #ifdef CONFIG_W1_SLAVE_DS2433_CRC - if (err) + if (data->cfg->page_count > W1_VALIDCRC_MAX) { + dev_err(&sl->dev, "page count too big for crc bitmap\n"); kfree(data); -#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ + return -EINVAL; + } + data->memory = kzalloc(data->cfg->eeprom_size, GFP_KERNEL); + if (!data->memory) { + kfree(data); + return -ENOMEM; + } + bitmap_zero(data->validcrc, data->cfg->page_count); +#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ + sl->family_data = data; - return err; + return 0; } static void w1_f23_remove_slave(struct w1_slave *sl) { -#ifdef CONFIG_W1_SLAVE_DS2433_CRC - kfree(sl->family_data); + struct w1_f23_data *data = sl->family_data; sl->family_data = NULL; -#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ - sysfs_remove_bin_file(&sl->dev.kobj, &w1_f23_bin_attr); +#ifdef CONFIG_W1_SLAVE_DS2433_CRC + kfree(data->memory); +#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ + kfree(data); } -static struct w1_family_ops w1_f23_fops = { +static const struct w1_family_ops w1_f23_fops = { + .add_slave = w1_f23_add_slave, + .remove_slave = w1_f23_remove_slave, + .groups = w1_f23_groups, +}; + +static const struct w1_family_ops w1_f43_fops = { .add_slave = w1_f23_add_slave, .remove_slave = w1_f23_remove_slave, + .groups = w1_f43_groups, }; static struct w1_family w1_family_23 = { @@ -309,15 +378,42 @@ static struct w1_family w1_family_23 = { .fops = &w1_f23_fops, }; -static int __init w1_f23_init(void) +static struct w1_family w1_family_43 = { + .fid = W1_EEPROM_DS28EC20, + .fops = &w1_f43_fops, +}; + +static int __init w1_ds2433_init(void) { - return w1_register_family(&w1_family_23); + int err; + + err = w1_register_family(&w1_family_23); + if (err) + return err; + + err = w1_register_family(&w1_family_43); + if (err) + goto err_43; + + return 0; + +err_43: + w1_unregister_family(&w1_family_23); + return err; } -static void __exit w1_f23_fini(void) +static void __exit w1_ds2433_exit(void) { w1_unregister_family(&w1_family_23); + w1_unregister_family(&w1_family_43); } -module_init(w1_f23_init); -module_exit(w1_f23_fini); +module_init(w1_ds2433_init); +module_exit(w1_ds2433_exit); + +MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); +MODULE_AUTHOR("Marc Ferland <marc.ferland@sonatest.com>"); +MODULE_DESCRIPTION("w1 family 23/43 driver for DS2433 (4kb) and DS28EC20 (20kb)"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS2433)); +MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS28EC20)); |
