Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * w1_ds250x.c - w1 family 09/0b/89/91 (DS250x) driver
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/module.h>
0008 #include <linux/moduleparam.h>
0009 #include <linux/device.h>
0010 #include <linux/types.h>
0011 #include <linux/delay.h>
0012 #include <linux/slab.h>
0013 #include <linux/crc16.h>
0014 
0015 #include <linux/w1.h>
0016 #include <linux/nvmem-provider.h>
0017 
0018 #define W1_DS2501_UNW_FAMILY    0x91
0019 #define W1_DS2501_SIZE          64
0020 
0021 #define W1_DS2502_FAMILY        0x09
0022 #define W1_DS2502_UNW_FAMILY    0x89
0023 #define W1_DS2502_SIZE          128
0024 
0025 #define W1_DS2505_FAMILY    0x0b
0026 #define W1_DS2505_SIZE      2048
0027 
0028 #define W1_PAGE_SIZE        32
0029 
0030 #define W1_EXT_READ_MEMORY  0xA5
0031 #define W1_READ_DATA_CRC        0xC3
0032 
0033 #define OFF2PG(off) ((off) / W1_PAGE_SIZE)
0034 
0035 #define CRC16_INIT      0
0036 #define CRC16_VALID     0xb001
0037 
0038 struct w1_eprom_data {
0039     size_t size;
0040     int (*read)(struct w1_slave *sl, int pageno);
0041     u8 eprom[W1_DS2505_SIZE];
0042     DECLARE_BITMAP(page_present, W1_DS2505_SIZE / W1_PAGE_SIZE);
0043     char nvmem_name[64];
0044 };
0045 
0046 static int w1_ds2502_read_page(struct w1_slave *sl, int pageno)
0047 {
0048     struct w1_eprom_data *data = sl->family_data;
0049     int pgoff = pageno * W1_PAGE_SIZE;
0050     int ret = -EIO;
0051     u8 buf[3];
0052     u8 crc8;
0053 
0054     if (test_bit(pageno, data->page_present))
0055         return 0; /* page already present */
0056 
0057     mutex_lock(&sl->master->bus_mutex);
0058 
0059     if (w1_reset_select_slave(sl))
0060         goto err;
0061 
0062     buf[0] = W1_READ_DATA_CRC;
0063     buf[1] = pgoff & 0xff;
0064     buf[2] = pgoff >> 8;
0065     w1_write_block(sl->master, buf, 3);
0066 
0067     crc8 = w1_read_8(sl->master);
0068     if (w1_calc_crc8(buf, 3) != crc8)
0069         goto err;
0070 
0071     w1_read_block(sl->master, &data->eprom[pgoff], W1_PAGE_SIZE);
0072 
0073     crc8 = w1_read_8(sl->master);
0074     if (w1_calc_crc8(&data->eprom[pgoff], W1_PAGE_SIZE) != crc8)
0075         goto err;
0076 
0077     set_bit(pageno, data->page_present); /* mark page present */
0078     ret = 0;
0079 err:
0080     mutex_unlock(&sl->master->bus_mutex);
0081     return ret;
0082 }
0083 
0084 static int w1_ds2505_read_page(struct w1_slave *sl, int pageno)
0085 {
0086     struct w1_eprom_data *data = sl->family_data;
0087     int redir_retries = 16;
0088     int pgoff, epoff;
0089     int ret = -EIO;
0090     u8 buf[6];
0091     u8 redir;
0092     u16 crc;
0093 
0094     if (test_bit(pageno, data->page_present))
0095         return 0; /* page already present */
0096 
0097     epoff = pgoff = pageno * W1_PAGE_SIZE;
0098     mutex_lock(&sl->master->bus_mutex);
0099 
0100 retry:
0101     if (w1_reset_select_slave(sl))
0102         goto err;
0103 
0104     buf[0] = W1_EXT_READ_MEMORY;
0105     buf[1] = pgoff & 0xff;
0106     buf[2] = pgoff >> 8;
0107     w1_write_block(sl->master, buf, 3);
0108     w1_read_block(sl->master, buf + 3, 3); /* redir, crc16 */
0109     redir = buf[3];
0110     crc = crc16(CRC16_INIT, buf, 6);
0111 
0112     if (crc != CRC16_VALID)
0113         goto err;
0114 
0115 
0116     if (redir != 0xff) {
0117         redir_retries--;
0118         if (redir_retries < 0)
0119             goto err;
0120 
0121         pgoff = (redir ^ 0xff) * W1_PAGE_SIZE;
0122         goto retry;
0123     }
0124 
0125     w1_read_block(sl->master, &data->eprom[epoff], W1_PAGE_SIZE);
0126     w1_read_block(sl->master, buf, 2); /* crc16 */
0127     crc = crc16(CRC16_INIT, &data->eprom[epoff], W1_PAGE_SIZE);
0128     crc = crc16(crc, buf, 2);
0129 
0130     if (crc != CRC16_VALID)
0131         goto err;
0132 
0133     set_bit(pageno, data->page_present);
0134     ret = 0;
0135 err:
0136     mutex_unlock(&sl->master->bus_mutex);
0137     return ret;
0138 }
0139 
0140 static int w1_nvmem_read(void *priv, unsigned int off, void *buf, size_t count)
0141 {
0142     struct w1_slave *sl = priv;
0143     struct w1_eprom_data *data = sl->family_data;
0144     size_t eprom_size = data->size;
0145     int ret;
0146     int i;
0147 
0148     if (off > eprom_size)
0149         return -EINVAL;
0150 
0151     if ((off + count) > eprom_size)
0152         count = eprom_size - off;
0153 
0154     i = OFF2PG(off);
0155     do {
0156         ret = data->read(sl, i++);
0157         if (ret < 0)
0158             return ret;
0159     } while (i < OFF2PG(off + count));
0160 
0161     memcpy(buf, &data->eprom[off], count);
0162     return 0;
0163 }
0164 
0165 static int w1_eprom_add_slave(struct w1_slave *sl)
0166 {
0167     struct w1_eprom_data *data;
0168     struct nvmem_device *nvmem;
0169     struct nvmem_config nvmem_cfg = {
0170         .dev = &sl->dev,
0171         .reg_read = w1_nvmem_read,
0172         .type = NVMEM_TYPE_OTP,
0173         .read_only = true,
0174         .word_size = 1,
0175         .priv = sl,
0176         .id = -1
0177     };
0178 
0179     data = devm_kzalloc(&sl->dev, sizeof(struct w1_eprom_data), GFP_KERNEL);
0180     if (!data)
0181         return -ENOMEM;
0182 
0183     sl->family_data = data;
0184     switch (sl->family->fid) {
0185     case W1_DS2501_UNW_FAMILY:
0186         data->size = W1_DS2501_SIZE;
0187         data->read = w1_ds2502_read_page;
0188         break;
0189     case W1_DS2502_FAMILY:
0190     case W1_DS2502_UNW_FAMILY:
0191         data->size = W1_DS2502_SIZE;
0192         data->read = w1_ds2502_read_page;
0193         break;
0194     case W1_DS2505_FAMILY:
0195         data->size = W1_DS2505_SIZE;
0196         data->read = w1_ds2505_read_page;
0197         break;
0198     }
0199 
0200     if (sl->master->bus_master->dev_id)
0201         snprintf(data->nvmem_name, sizeof(data->nvmem_name),
0202              "%s-%02x-%012llx",
0203              sl->master->bus_master->dev_id, sl->reg_num.family,
0204              (unsigned long long)sl->reg_num.id);
0205     else
0206         snprintf(data->nvmem_name, sizeof(data->nvmem_name),
0207              "%02x-%012llx",
0208              sl->reg_num.family,
0209              (unsigned long long)sl->reg_num.id);
0210 
0211     nvmem_cfg.name = data->nvmem_name;
0212     nvmem_cfg.size = data->size;
0213 
0214     nvmem = devm_nvmem_register(&sl->dev, &nvmem_cfg);
0215     return PTR_ERR_OR_ZERO(nvmem);
0216 }
0217 
0218 static const struct w1_family_ops w1_eprom_fops = {
0219     .add_slave  = w1_eprom_add_slave,
0220 };
0221 
0222 static struct w1_family w1_family_09 = {
0223     .fid = W1_DS2502_FAMILY,
0224     .fops = &w1_eprom_fops,
0225 };
0226 
0227 static struct w1_family w1_family_0b = {
0228     .fid = W1_DS2505_FAMILY,
0229     .fops = &w1_eprom_fops,
0230 };
0231 
0232 static struct w1_family w1_family_89 = {
0233     .fid = W1_DS2502_UNW_FAMILY,
0234     .fops = &w1_eprom_fops,
0235 };
0236 
0237 static struct w1_family w1_family_91 = {
0238     .fid = W1_DS2501_UNW_FAMILY,
0239     .fops = &w1_eprom_fops,
0240 };
0241 
0242 static int __init w1_ds250x_init(void)
0243 {
0244     int err;
0245 
0246     err = w1_register_family(&w1_family_09);
0247     if (err)
0248         return err;
0249 
0250     err = w1_register_family(&w1_family_0b);
0251     if (err)
0252         goto err_0b;
0253 
0254     err = w1_register_family(&w1_family_89);
0255     if (err)
0256         goto err_89;
0257 
0258     err = w1_register_family(&w1_family_91);
0259     if (err)
0260         goto err_91;
0261 
0262     return 0;
0263 
0264 err_91:
0265     w1_unregister_family(&w1_family_89);
0266 err_89:
0267     w1_unregister_family(&w1_family_0b);
0268 err_0b:
0269     w1_unregister_family(&w1_family_09);
0270     return err;
0271 }
0272 
0273 static void __exit w1_ds250x_exit(void)
0274 {
0275     w1_unregister_family(&w1_family_09);
0276     w1_unregister_family(&w1_family_0b);
0277     w1_unregister_family(&w1_family_89);
0278     w1_unregister_family(&w1_family_91);
0279 }
0280 
0281 module_init(w1_ds250x_init);
0282 module_exit(w1_ds250x_exit);
0283 
0284 MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfe@suse.de>");
0285 MODULE_DESCRIPTION("w1 family driver for DS250x Add Only Memory");
0286 MODULE_LICENSE("GPL");
0287 MODULE_ALIAS("w1-family-" __stringify(W1_DS2502_FAMILY));
0288 MODULE_ALIAS("w1-family-" __stringify(W1_DS2505_FAMILY));
0289 MODULE_ALIAS("w1-family-" __stringify(W1_DS2501_UNW_FAMILY));
0290 MODULE_ALIAS("w1-family-" __stringify(W1_DS2502_UNW_FAMILY));