Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * 1-Wire implementation for the ds2438 chip
0004  *
0005  * Copyright (c) 2017 Mariusz Bialonczyk <manio@skyboo.net>
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/device.h>
0011 #include <linux/types.h>
0012 #include <linux/delay.h>
0013 
0014 #include <linux/w1.h>
0015 
0016 #define W1_FAMILY_DS2438        0x26
0017 
0018 #define W1_DS2438_RETRIES       3
0019 
0020 /* Memory commands */
0021 #define W1_DS2438_READ_SCRATCH      0xBE
0022 #define W1_DS2438_WRITE_SCRATCH     0x4E
0023 #define W1_DS2438_COPY_SCRATCH      0x48
0024 #define W1_DS2438_RECALL_MEMORY     0xB8
0025 /* Register commands */
0026 #define W1_DS2438_CONVERT_TEMP      0x44
0027 #define W1_DS2438_CONVERT_VOLTAGE   0xB4
0028 
0029 #define DS2438_PAGE_SIZE        8
0030 #define DS2438_ADC_INPUT_VAD        0
0031 #define DS2438_ADC_INPUT_VDD        1
0032 #define DS2438_MAX_CONVERSION_TIME  10      /* ms */
0033 
0034 /* Page #0 definitions */
0035 #define DS2438_STATUS_REG       0x00        /* Status/Configuration Register */
0036 #define DS2438_STATUS_IAD       (1 << 0)    /* Current A/D Control Bit */
0037 #define DS2438_STATUS_CA        (1 << 1)    /* Current Accumulator Configuration */
0038 #define DS2438_STATUS_EE        (1 << 2)    /* Current Accumulator Shadow Selector bit */
0039 #define DS2438_STATUS_AD        (1 << 3)    /* Voltage A/D Input Select Bit */
0040 #define DS2438_STATUS_TB        (1 << 4)    /* Temperature Busy Flag */
0041 #define DS2438_STATUS_NVB       (1 << 5)    /* Nonvolatile Memory Busy Flag */
0042 #define DS2438_STATUS_ADB       (1 << 6)    /* A/D Converter Busy Flag */
0043 
0044 #define DS2438_TEMP_LSB         0x01
0045 #define DS2438_TEMP_MSB         0x02
0046 #define DS2438_VOLTAGE_LSB      0x03
0047 #define DS2438_VOLTAGE_MSB      0x04
0048 #define DS2438_CURRENT_LSB      0x05
0049 #define DS2438_CURRENT_MSB      0x06
0050 #define DS2438_THRESHOLD        0x07
0051 
0052 /* Page #1 definitions */
0053 #define DS2438_ETM_0            0x00
0054 #define DS2438_ETM_1            0x01
0055 #define DS2438_ETM_2            0x02
0056 #define DS2438_ETM_3            0x03
0057 #define DS2438_ICA          0x04
0058 #define DS2438_OFFSET_LSB       0x05
0059 #define DS2438_OFFSET_MSB       0x06
0060 
0061 static int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf)
0062 {
0063     unsigned int retries = W1_DS2438_RETRIES;
0064     u8 w1_buf[2];
0065     u8 crc;
0066     size_t count;
0067 
0068     while (retries--) {
0069         crc = 0;
0070 
0071         if (w1_reset_select_slave(sl))
0072             continue;
0073         w1_buf[0] = W1_DS2438_RECALL_MEMORY;
0074         w1_buf[1] = (u8)pageno;
0075         w1_write_block(sl->master, w1_buf, 2);
0076 
0077         if (w1_reset_select_slave(sl))
0078             continue;
0079         w1_buf[0] = W1_DS2438_READ_SCRATCH;
0080         w1_buf[1] = (u8)pageno;
0081         w1_write_block(sl->master, w1_buf, 2);
0082 
0083         count = w1_read_block(sl->master, buf, DS2438_PAGE_SIZE + 1);
0084         if (count == DS2438_PAGE_SIZE + 1) {
0085             crc = w1_calc_crc8(buf, DS2438_PAGE_SIZE);
0086 
0087             /* check for correct CRC */
0088             if ((u8)buf[DS2438_PAGE_SIZE] == crc)
0089                 return 0;
0090         }
0091     }
0092     return -1;
0093 }
0094 
0095 static int w1_ds2438_get_temperature(struct w1_slave *sl, int16_t *temperature)
0096 {
0097     unsigned int retries = W1_DS2438_RETRIES;
0098     u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
0099     unsigned int tm = DS2438_MAX_CONVERSION_TIME;
0100     unsigned long sleep_rem;
0101     int ret;
0102 
0103     mutex_lock(&sl->master->bus_mutex);
0104 
0105     while (retries--) {
0106         if (w1_reset_select_slave(sl))
0107             continue;
0108         w1_write_8(sl->master, W1_DS2438_CONVERT_TEMP);
0109 
0110         mutex_unlock(&sl->master->bus_mutex);
0111         sleep_rem = msleep_interruptible(tm);
0112         if (sleep_rem != 0) {
0113             ret = -1;
0114             goto post_unlock;
0115         }
0116 
0117         if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) {
0118             ret = -1;
0119             goto post_unlock;
0120         }
0121 
0122         break;
0123     }
0124 
0125     if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
0126         *temperature = (((int16_t) w1_buf[DS2438_TEMP_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_TEMP_LSB]);
0127         ret = 0;
0128     } else
0129         ret = -1;
0130 
0131     mutex_unlock(&sl->master->bus_mutex);
0132 
0133 post_unlock:
0134     return ret;
0135 }
0136 
0137 static int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value)
0138 {
0139     unsigned int retries = W1_DS2438_RETRIES;
0140     u8 w1_buf[3];
0141     u8 status;
0142     int perform_write = 0;
0143 
0144     while (retries--) {
0145         if (w1_reset_select_slave(sl))
0146             continue;
0147         w1_buf[0] = W1_DS2438_RECALL_MEMORY;
0148         w1_buf[1] = 0x00;
0149         w1_write_block(sl->master, w1_buf, 2);
0150 
0151         if (w1_reset_select_slave(sl))
0152             continue;
0153         w1_buf[0] = W1_DS2438_READ_SCRATCH;
0154         w1_buf[1] = 0x00;
0155         w1_write_block(sl->master, w1_buf, 2);
0156 
0157         /* reading one byte of result */
0158         status = w1_read_8(sl->master);
0159 
0160         /* if bit0=1, set a value to a mask for easy compare */
0161         if (value)
0162             value = mask;
0163 
0164         if ((status & mask) == value)
0165             return 0;   /* already set as requested */
0166 
0167         /* changing bit */
0168         status ^= mask;
0169         perform_write = 1;
0170 
0171         break;
0172     }
0173 
0174     if (perform_write) {
0175         retries = W1_DS2438_RETRIES;
0176         while (retries--) {
0177             if (w1_reset_select_slave(sl))
0178                 continue;
0179             w1_buf[0] = W1_DS2438_WRITE_SCRATCH;
0180             w1_buf[1] = 0x00;
0181             w1_buf[2] = status;
0182             w1_write_block(sl->master, w1_buf, 3);
0183 
0184             if (w1_reset_select_slave(sl))
0185                 continue;
0186             w1_buf[0] = W1_DS2438_COPY_SCRATCH;
0187             w1_buf[1] = 0x00;
0188             w1_write_block(sl->master, w1_buf, 2);
0189 
0190             return 0;
0191         }
0192     }
0193     return -1;
0194 }
0195 
0196 static int w1_ds2438_change_offset_register(struct w1_slave *sl, u8 *value)
0197 {
0198     unsigned int retries = W1_DS2438_RETRIES;
0199     u8 w1_buf[9];
0200     u8 w1_page1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
0201 
0202     if (w1_ds2438_get_page(sl, 1, w1_page1_buf) == 0) {
0203         memcpy(&w1_buf[2], w1_page1_buf, DS2438_PAGE_SIZE - 1); /* last register reserved */
0204         w1_buf[7] = value[0]; /* change only offset register */
0205         w1_buf[8] = value[1];
0206         while (retries--) {
0207             if (w1_reset_select_slave(sl))
0208                 continue;
0209             w1_buf[0] = W1_DS2438_WRITE_SCRATCH;
0210             w1_buf[1] = 0x01; /* write to page 1 */
0211             w1_write_block(sl->master, w1_buf, 9);
0212 
0213             if (w1_reset_select_slave(sl))
0214                 continue;
0215             w1_buf[0] = W1_DS2438_COPY_SCRATCH;
0216             w1_buf[1] = 0x01;
0217             w1_write_block(sl->master, w1_buf, 2);
0218             return 0;
0219         }
0220     }
0221     return -1;
0222 }
0223 
0224 static int w1_ds2438_get_voltage(struct w1_slave *sl,
0225                  int adc_input, uint16_t *voltage)
0226 {
0227     unsigned int retries = W1_DS2438_RETRIES;
0228     u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
0229     unsigned int tm = DS2438_MAX_CONVERSION_TIME;
0230     unsigned long sleep_rem;
0231     int ret;
0232 
0233     mutex_lock(&sl->master->bus_mutex);
0234 
0235     if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_AD, adc_input)) {
0236         ret = -1;
0237         goto pre_unlock;
0238     }
0239 
0240     while (retries--) {
0241         if (w1_reset_select_slave(sl))
0242             continue;
0243         w1_write_8(sl->master, W1_DS2438_CONVERT_VOLTAGE);
0244 
0245         mutex_unlock(&sl->master->bus_mutex);
0246         sleep_rem = msleep_interruptible(tm);
0247         if (sleep_rem != 0) {
0248             ret = -1;
0249             goto post_unlock;
0250         }
0251 
0252         if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) {
0253             ret = -1;
0254             goto post_unlock;
0255         }
0256 
0257         break;
0258     }
0259 
0260     if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
0261         *voltage = (((uint16_t) w1_buf[DS2438_VOLTAGE_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_VOLTAGE_LSB]);
0262         ret = 0;
0263     } else
0264         ret = -1;
0265 
0266 pre_unlock:
0267     mutex_unlock(&sl->master->bus_mutex);
0268 
0269 post_unlock:
0270     return ret;
0271 }
0272 
0273 static int w1_ds2438_get_current(struct w1_slave *sl, int16_t *voltage)
0274 {
0275     u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
0276     int ret;
0277 
0278     mutex_lock(&sl->master->bus_mutex);
0279 
0280     if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
0281         /* The voltage measured across current sense resistor RSENS. */
0282         *voltage = (((int16_t) w1_buf[DS2438_CURRENT_MSB]) << 8) | ((int16_t) w1_buf[DS2438_CURRENT_LSB]);
0283         ret = 0;
0284     } else
0285         ret = -1;
0286 
0287     mutex_unlock(&sl->master->bus_mutex);
0288 
0289     return ret;
0290 }
0291 
0292 static ssize_t iad_write(struct file *filp, struct kobject *kobj,
0293              struct bin_attribute *bin_attr, char *buf,
0294              loff_t off, size_t count)
0295 {
0296     struct w1_slave *sl = kobj_to_w1_slave(kobj);
0297     int ret;
0298 
0299     if (count != 1 || off != 0)
0300         return -EFAULT;
0301 
0302     mutex_lock(&sl->master->bus_mutex);
0303 
0304     if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_IAD, *buf & 0x01) == 0)
0305         ret = 1;
0306     else
0307         ret = -EIO;
0308 
0309     mutex_unlock(&sl->master->bus_mutex);
0310 
0311     return ret;
0312 }
0313 
0314 static ssize_t iad_read(struct file *filp, struct kobject *kobj,
0315             struct bin_attribute *bin_attr, char *buf,
0316             loff_t off, size_t count)
0317 {
0318     struct w1_slave *sl = kobj_to_w1_slave(kobj);
0319     int ret;
0320     int16_t voltage;
0321 
0322     if (off != 0)
0323         return 0;
0324     if (!buf)
0325         return -EINVAL;
0326 
0327     if (w1_ds2438_get_current(sl, &voltage) == 0)
0328         ret = snprintf(buf, count, "%i\n", voltage);
0329     else
0330         ret = -EIO;
0331 
0332     return ret;
0333 }
0334 
0335 static ssize_t page0_read(struct file *filp, struct kobject *kobj,
0336               struct bin_attribute *bin_attr, char *buf,
0337               loff_t off, size_t count)
0338 {
0339     struct w1_slave *sl = kobj_to_w1_slave(kobj);
0340     int ret;
0341     u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
0342 
0343     if (off != 0)
0344         return 0;
0345     if (!buf)
0346         return -EINVAL;
0347 
0348     mutex_lock(&sl->master->bus_mutex);
0349 
0350     /* Read no more than page0 size */
0351     if (count > DS2438_PAGE_SIZE)
0352         count = DS2438_PAGE_SIZE;
0353 
0354     if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
0355         memcpy(buf, &w1_buf, count);
0356         ret = count;
0357     } else
0358         ret = -EIO;
0359 
0360     mutex_unlock(&sl->master->bus_mutex);
0361 
0362     return ret;
0363 }
0364 
0365 static ssize_t page1_read(struct file *filp, struct kobject *kobj,
0366               struct bin_attribute *bin_attr, char *buf,
0367               loff_t off, size_t count)
0368 {
0369     struct w1_slave *sl = kobj_to_w1_slave(kobj);
0370     int ret;
0371     u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
0372 
0373     if (off != 0)
0374         return 0;
0375     if (!buf)
0376         return -EINVAL;
0377 
0378     mutex_lock(&sl->master->bus_mutex);
0379 
0380     /* Read no more than page1 size */
0381     if (count > DS2438_PAGE_SIZE)
0382         count = DS2438_PAGE_SIZE;
0383 
0384     if (w1_ds2438_get_page(sl, 1, w1_buf) == 0) {
0385         memcpy(buf, &w1_buf, count);
0386         ret = count;
0387     } else
0388         ret = -EIO;
0389 
0390     mutex_unlock(&sl->master->bus_mutex);
0391 
0392     return ret;
0393 }
0394 
0395 static ssize_t offset_write(struct file *filp, struct kobject *kobj,
0396                 struct bin_attribute *bin_attr, char *buf,
0397                 loff_t off, size_t count)
0398 {
0399     struct w1_slave *sl = kobj_to_w1_slave(kobj);
0400     int ret;
0401 
0402     mutex_lock(&sl->master->bus_mutex);
0403 
0404     if (w1_ds2438_change_offset_register(sl, buf) == 0)
0405         ret = count;
0406     else
0407         ret = -EIO;
0408 
0409     mutex_unlock(&sl->master->bus_mutex);
0410 
0411     return ret;
0412 }
0413 
0414 static ssize_t temperature_read(struct file *filp, struct kobject *kobj,
0415                 struct bin_attribute *bin_attr, char *buf,
0416                 loff_t off, size_t count)
0417 {
0418     struct w1_slave *sl = kobj_to_w1_slave(kobj);
0419     int ret;
0420     int16_t temp;
0421 
0422     if (off != 0)
0423         return 0;
0424     if (!buf)
0425         return -EINVAL;
0426 
0427     if (w1_ds2438_get_temperature(sl, &temp) == 0)
0428         ret = snprintf(buf, count, "%i\n", temp);
0429     else
0430         ret = -EIO;
0431 
0432     return ret;
0433 }
0434 
0435 static ssize_t vad_read(struct file *filp, struct kobject *kobj,
0436             struct bin_attribute *bin_attr, char *buf,
0437             loff_t off, size_t count)
0438 {
0439     struct w1_slave *sl = kobj_to_w1_slave(kobj);
0440     int ret;
0441     uint16_t voltage;
0442 
0443     if (off != 0)
0444         return 0;
0445     if (!buf)
0446         return -EINVAL;
0447 
0448     if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0)
0449         ret = snprintf(buf, count, "%u\n", voltage);
0450     else
0451         ret = -EIO;
0452 
0453     return ret;
0454 }
0455 
0456 static ssize_t vdd_read(struct file *filp, struct kobject *kobj,
0457             struct bin_attribute *bin_attr, char *buf,
0458             loff_t off, size_t count)
0459 {
0460     struct w1_slave *sl = kobj_to_w1_slave(kobj);
0461     int ret;
0462     uint16_t voltage;
0463 
0464     if (off != 0)
0465         return 0;
0466     if (!buf)
0467         return -EINVAL;
0468 
0469     if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0)
0470         ret = snprintf(buf, count, "%u\n", voltage);
0471     else
0472         ret = -EIO;
0473 
0474     return ret;
0475 }
0476 
0477 static BIN_ATTR_RW(iad, 0);
0478 static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE);
0479 static BIN_ATTR_RO(page1, DS2438_PAGE_SIZE);
0480 static BIN_ATTR_WO(offset, 2);
0481 static BIN_ATTR_RO(temperature, 0/* real length varies */);
0482 static BIN_ATTR_RO(vad, 0/* real length varies */);
0483 static BIN_ATTR_RO(vdd, 0/* real length varies */);
0484 
0485 static struct bin_attribute *w1_ds2438_bin_attrs[] = {
0486     &bin_attr_iad,
0487     &bin_attr_page0,
0488     &bin_attr_page1,
0489     &bin_attr_offset,
0490     &bin_attr_temperature,
0491     &bin_attr_vad,
0492     &bin_attr_vdd,
0493     NULL,
0494 };
0495 
0496 static const struct attribute_group w1_ds2438_group = {
0497     .bin_attrs = w1_ds2438_bin_attrs,
0498 };
0499 
0500 static const struct attribute_group *w1_ds2438_groups[] = {
0501     &w1_ds2438_group,
0502     NULL,
0503 };
0504 
0505 static const struct w1_family_ops w1_ds2438_fops = {
0506     .groups     = w1_ds2438_groups,
0507 };
0508 
0509 static struct w1_family w1_ds2438_family = {
0510     .fid = W1_FAMILY_DS2438,
0511     .fops = &w1_ds2438_fops,
0512 };
0513 module_w1_family(w1_ds2438_family);
0514 
0515 MODULE_LICENSE("GPL");
0516 MODULE_AUTHOR("Mariusz Bialonczyk <manio@skyboo.net>");
0517 MODULE_DESCRIPTION("1-wire driver for Maxim/Dallas DS2438 Smart Battery Monitor");
0518 MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2438));