1e3af95e6SMariusz Bialonczyk /* 2e3af95e6SMariusz Bialonczyk * 1-Wire implementation for the ds2438 chip 3e3af95e6SMariusz Bialonczyk * 4e3af95e6SMariusz Bialonczyk * Copyright (c) 2017 Mariusz Bialonczyk <manio@skyboo.net> 5e3af95e6SMariusz Bialonczyk * 6e3af95e6SMariusz Bialonczyk * This source code is licensed under the GNU General Public License, 7e3af95e6SMariusz Bialonczyk * Version 2. See the file COPYING for more details. 8e3af95e6SMariusz Bialonczyk */ 9e3af95e6SMariusz Bialonczyk 10e3af95e6SMariusz Bialonczyk #include <linux/kernel.h> 11e3af95e6SMariusz Bialonczyk #include <linux/module.h> 12e3af95e6SMariusz Bialonczyk #include <linux/device.h> 13e3af95e6SMariusz Bialonczyk #include <linux/types.h> 14e3af95e6SMariusz Bialonczyk #include <linux/delay.h> 15e3af95e6SMariusz Bialonczyk 16de0d6dbdSAndrew F. Davis #include <linux/w1.h> 17de0d6dbdSAndrew F. Davis 18de0d6dbdSAndrew F. Davis #define W1_FAMILY_DS2438 0x26 19e3af95e6SMariusz Bialonczyk 20e3af95e6SMariusz Bialonczyk #define W1_DS2438_RETRIES 3 21e3af95e6SMariusz Bialonczyk 22e3af95e6SMariusz Bialonczyk /* Memory commands */ 23e3af95e6SMariusz Bialonczyk #define W1_DS2438_READ_SCRATCH 0xBE 24e3af95e6SMariusz Bialonczyk #define W1_DS2438_WRITE_SCRATCH 0x4E 25e3af95e6SMariusz Bialonczyk #define W1_DS2438_COPY_SCRATCH 0x48 26e3af95e6SMariusz Bialonczyk #define W1_DS2438_RECALL_MEMORY 0xB8 27e3af95e6SMariusz Bialonczyk /* Register commands */ 28e3af95e6SMariusz Bialonczyk #define W1_DS2438_CONVERT_TEMP 0x44 29e3af95e6SMariusz Bialonczyk #define W1_DS2438_CONVERT_VOLTAGE 0xB4 30e3af95e6SMariusz Bialonczyk 31e3af95e6SMariusz Bialonczyk #define DS2438_PAGE_SIZE 8 32e3af95e6SMariusz Bialonczyk #define DS2438_ADC_INPUT_VAD 0 33e3af95e6SMariusz Bialonczyk #define DS2438_ADC_INPUT_VDD 1 34e3af95e6SMariusz Bialonczyk #define DS2438_MAX_CONVERSION_TIME 10 /* ms */ 35e3af95e6SMariusz Bialonczyk 36e3af95e6SMariusz Bialonczyk /* Page #0 definitions */ 37e3af95e6SMariusz Bialonczyk #define DS2438_STATUS_REG 0x00 /* Status/Configuration Register */ 38e3af95e6SMariusz Bialonczyk #define DS2438_STATUS_IAD (1 << 0) /* Current A/D Control Bit */ 39e3af95e6SMariusz Bialonczyk #define DS2438_STATUS_CA (1 << 1) /* Current Accumulator Configuration */ 40e3af95e6SMariusz Bialonczyk #define DS2438_STATUS_EE (1 << 2) /* Current Accumulator Shadow Selector bit */ 41e3af95e6SMariusz Bialonczyk #define DS2438_STATUS_AD (1 << 3) /* Voltage A/D Input Select Bit */ 42e3af95e6SMariusz Bialonczyk #define DS2438_STATUS_TB (1 << 4) /* Temperature Busy Flag */ 43e3af95e6SMariusz Bialonczyk #define DS2438_STATUS_NVB (1 << 5) /* Nonvolatile Memory Busy Flag */ 44e3af95e6SMariusz Bialonczyk #define DS2438_STATUS_ADB (1 << 6) /* A/D Converter Busy Flag */ 45e3af95e6SMariusz Bialonczyk 46e3af95e6SMariusz Bialonczyk #define DS2438_TEMP_LSB 0x01 47e3af95e6SMariusz Bialonczyk #define DS2438_TEMP_MSB 0x02 48e3af95e6SMariusz Bialonczyk #define DS2438_VOLTAGE_LSB 0x03 49e3af95e6SMariusz Bialonczyk #define DS2438_VOLTAGE_MSB 0x04 50e3af95e6SMariusz Bialonczyk #define DS2438_CURRENT_LSB 0x05 51e3af95e6SMariusz Bialonczyk #define DS2438_CURRENT_MSB 0x06 52e3af95e6SMariusz Bialonczyk #define DS2438_THRESHOLD 0x07 53e3af95e6SMariusz Bialonczyk 54e5cf84e8SColin Ian King static int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf) 55e3af95e6SMariusz Bialonczyk { 56e3af95e6SMariusz Bialonczyk unsigned int retries = W1_DS2438_RETRIES; 57e3af95e6SMariusz Bialonczyk u8 w1_buf[2]; 58e3af95e6SMariusz Bialonczyk u8 crc; 59e3af95e6SMariusz Bialonczyk size_t count; 60e3af95e6SMariusz Bialonczyk 61e3af95e6SMariusz Bialonczyk while (retries--) { 62e3af95e6SMariusz Bialonczyk crc = 0; 63e3af95e6SMariusz Bialonczyk 64e3af95e6SMariusz Bialonczyk if (w1_reset_select_slave(sl)) 65e3af95e6SMariusz Bialonczyk continue; 66e3af95e6SMariusz Bialonczyk w1_buf[0] = W1_DS2438_RECALL_MEMORY; 67e3af95e6SMariusz Bialonczyk w1_buf[1] = 0x00; 68e3af95e6SMariusz Bialonczyk w1_write_block(sl->master, w1_buf, 2); 69e3af95e6SMariusz Bialonczyk 70e3af95e6SMariusz Bialonczyk if (w1_reset_select_slave(sl)) 71e3af95e6SMariusz Bialonczyk continue; 72e3af95e6SMariusz Bialonczyk w1_buf[0] = W1_DS2438_READ_SCRATCH; 73e3af95e6SMariusz Bialonczyk w1_buf[1] = 0x00; 74e3af95e6SMariusz Bialonczyk w1_write_block(sl->master, w1_buf, 2); 75e3af95e6SMariusz Bialonczyk 76e3af95e6SMariusz Bialonczyk count = w1_read_block(sl->master, buf, DS2438_PAGE_SIZE + 1); 77e3af95e6SMariusz Bialonczyk if (count == DS2438_PAGE_SIZE + 1) { 78e3af95e6SMariusz Bialonczyk crc = w1_calc_crc8(buf, DS2438_PAGE_SIZE); 79e3af95e6SMariusz Bialonczyk 80e3af95e6SMariusz Bialonczyk /* check for correct CRC */ 81e3af95e6SMariusz Bialonczyk if ((u8)buf[DS2438_PAGE_SIZE] == crc) 82e3af95e6SMariusz Bialonczyk return 0; 83e3af95e6SMariusz Bialonczyk } 84e3af95e6SMariusz Bialonczyk } 85e3af95e6SMariusz Bialonczyk return -1; 86e3af95e6SMariusz Bialonczyk } 87e3af95e6SMariusz Bialonczyk 88e5cf84e8SColin Ian King static int w1_ds2438_get_temperature(struct w1_slave *sl, int16_t *temperature) 89e3af95e6SMariusz Bialonczyk { 90e3af95e6SMariusz Bialonczyk unsigned int retries = W1_DS2438_RETRIES; 91e3af95e6SMariusz Bialonczyk u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; 92e3af95e6SMariusz Bialonczyk unsigned int tm = DS2438_MAX_CONVERSION_TIME; 93e3af95e6SMariusz Bialonczyk unsigned long sleep_rem; 94e3af95e6SMariusz Bialonczyk int ret; 95e3af95e6SMariusz Bialonczyk 96e3af95e6SMariusz Bialonczyk mutex_lock(&sl->master->bus_mutex); 97e3af95e6SMariusz Bialonczyk 98e3af95e6SMariusz Bialonczyk while (retries--) { 99e3af95e6SMariusz Bialonczyk if (w1_reset_select_slave(sl)) 100e3af95e6SMariusz Bialonczyk continue; 101e3af95e6SMariusz Bialonczyk w1_write_8(sl->master, W1_DS2438_CONVERT_TEMP); 102e3af95e6SMariusz Bialonczyk 103e3af95e6SMariusz Bialonczyk mutex_unlock(&sl->master->bus_mutex); 104e3af95e6SMariusz Bialonczyk sleep_rem = msleep_interruptible(tm); 105e3af95e6SMariusz Bialonczyk if (sleep_rem != 0) { 106e3af95e6SMariusz Bialonczyk ret = -1; 107e3af95e6SMariusz Bialonczyk goto post_unlock; 108e3af95e6SMariusz Bialonczyk } 109e3af95e6SMariusz Bialonczyk 110e3af95e6SMariusz Bialonczyk if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) { 111e3af95e6SMariusz Bialonczyk ret = -1; 112e3af95e6SMariusz Bialonczyk goto post_unlock; 113e3af95e6SMariusz Bialonczyk } 114e3af95e6SMariusz Bialonczyk 115e3af95e6SMariusz Bialonczyk break; 116e3af95e6SMariusz Bialonczyk } 117e3af95e6SMariusz Bialonczyk 118e3af95e6SMariusz Bialonczyk if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { 119e3af95e6SMariusz Bialonczyk *temperature = (((int16_t) w1_buf[DS2438_TEMP_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_TEMP_LSB]); 120e3af95e6SMariusz Bialonczyk ret = 0; 121e3af95e6SMariusz Bialonczyk } else 122e3af95e6SMariusz Bialonczyk ret = -1; 123e3af95e6SMariusz Bialonczyk 124e3af95e6SMariusz Bialonczyk mutex_unlock(&sl->master->bus_mutex); 125e3af95e6SMariusz Bialonczyk 126e3af95e6SMariusz Bialonczyk post_unlock: 127e3af95e6SMariusz Bialonczyk return ret; 128e3af95e6SMariusz Bialonczyk } 129e3af95e6SMariusz Bialonczyk 130e5cf84e8SColin Ian King static int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value) 131e3af95e6SMariusz Bialonczyk { 132e3af95e6SMariusz Bialonczyk unsigned int retries = W1_DS2438_RETRIES; 133e3af95e6SMariusz Bialonczyk u8 w1_buf[3]; 134e3af95e6SMariusz Bialonczyk u8 status; 135e3af95e6SMariusz Bialonczyk int perform_write = 0; 136e3af95e6SMariusz Bialonczyk 137e3af95e6SMariusz Bialonczyk while (retries--) { 138e3af95e6SMariusz Bialonczyk if (w1_reset_select_slave(sl)) 139e3af95e6SMariusz Bialonczyk continue; 140e3af95e6SMariusz Bialonczyk w1_buf[0] = W1_DS2438_RECALL_MEMORY; 141e3af95e6SMariusz Bialonczyk w1_buf[1] = 0x00; 142e3af95e6SMariusz Bialonczyk w1_write_block(sl->master, w1_buf, 2); 143e3af95e6SMariusz Bialonczyk 144e3af95e6SMariusz Bialonczyk if (w1_reset_select_slave(sl)) 145e3af95e6SMariusz Bialonczyk continue; 146e3af95e6SMariusz Bialonczyk w1_buf[0] = W1_DS2438_READ_SCRATCH; 147e3af95e6SMariusz Bialonczyk w1_buf[1] = 0x00; 148e3af95e6SMariusz Bialonczyk w1_write_block(sl->master, w1_buf, 2); 149e3af95e6SMariusz Bialonczyk 150e3af95e6SMariusz Bialonczyk /* reading one byte of result */ 151e3af95e6SMariusz Bialonczyk status = w1_read_8(sl->master); 152e3af95e6SMariusz Bialonczyk 153e3af95e6SMariusz Bialonczyk /* if bit0=1, set a value to a mask for easy compare */ 154e3af95e6SMariusz Bialonczyk if (value) 155e3af95e6SMariusz Bialonczyk value = mask; 156e3af95e6SMariusz Bialonczyk 157e3af95e6SMariusz Bialonczyk if ((status & mask) == value) 158e3af95e6SMariusz Bialonczyk return 0; /* already set as requested */ 159e3af95e6SMariusz Bialonczyk else { 160e3af95e6SMariusz Bialonczyk /* changing bit */ 161e3af95e6SMariusz Bialonczyk status ^= mask; 162e3af95e6SMariusz Bialonczyk perform_write = 1; 163e3af95e6SMariusz Bialonczyk } 164e3af95e6SMariusz Bialonczyk break; 165e3af95e6SMariusz Bialonczyk } 166e3af95e6SMariusz Bialonczyk 167e3af95e6SMariusz Bialonczyk if (perform_write) { 168e3af95e6SMariusz Bialonczyk retries = W1_DS2438_RETRIES; 169e3af95e6SMariusz Bialonczyk while (retries--) { 170e3af95e6SMariusz Bialonczyk if (w1_reset_select_slave(sl)) 171e3af95e6SMariusz Bialonczyk continue; 172e3af95e6SMariusz Bialonczyk w1_buf[0] = W1_DS2438_WRITE_SCRATCH; 173e3af95e6SMariusz Bialonczyk w1_buf[1] = 0x00; 174e3af95e6SMariusz Bialonczyk w1_buf[2] = status; 175e3af95e6SMariusz Bialonczyk w1_write_block(sl->master, w1_buf, 3); 176e3af95e6SMariusz Bialonczyk 177e3af95e6SMariusz Bialonczyk if (w1_reset_select_slave(sl)) 178e3af95e6SMariusz Bialonczyk continue; 179e3af95e6SMariusz Bialonczyk w1_buf[0] = W1_DS2438_COPY_SCRATCH; 180e3af95e6SMariusz Bialonczyk w1_buf[1] = 0x00; 181e3af95e6SMariusz Bialonczyk w1_write_block(sl->master, w1_buf, 2); 182e3af95e6SMariusz Bialonczyk 183e3af95e6SMariusz Bialonczyk return 0; 184e3af95e6SMariusz Bialonczyk } 185e3af95e6SMariusz Bialonczyk } 186e3af95e6SMariusz Bialonczyk return -1; 187e3af95e6SMariusz Bialonczyk } 188e3af95e6SMariusz Bialonczyk 189*6eaafbb6SJulien Folly static int w1_ds2438_get_voltage(struct w1_slave *sl, 190e5cf84e8SColin Ian King int adc_input, uint16_t *voltage) 191e3af95e6SMariusz Bialonczyk { 192e3af95e6SMariusz Bialonczyk unsigned int retries = W1_DS2438_RETRIES; 193e3af95e6SMariusz Bialonczyk u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; 194e3af95e6SMariusz Bialonczyk unsigned int tm = DS2438_MAX_CONVERSION_TIME; 195e3af95e6SMariusz Bialonczyk unsigned long sleep_rem; 196e3af95e6SMariusz Bialonczyk int ret; 197e3af95e6SMariusz Bialonczyk 198e3af95e6SMariusz Bialonczyk mutex_lock(&sl->master->bus_mutex); 199e3af95e6SMariusz Bialonczyk 200e3af95e6SMariusz Bialonczyk if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_AD, adc_input)) { 201e3af95e6SMariusz Bialonczyk ret = -1; 202e3af95e6SMariusz Bialonczyk goto pre_unlock; 203e3af95e6SMariusz Bialonczyk } 204e3af95e6SMariusz Bialonczyk 205e3af95e6SMariusz Bialonczyk while (retries--) { 206e3af95e6SMariusz Bialonczyk if (w1_reset_select_slave(sl)) 207e3af95e6SMariusz Bialonczyk continue; 208e3af95e6SMariusz Bialonczyk w1_write_8(sl->master, W1_DS2438_CONVERT_VOLTAGE); 209e3af95e6SMariusz Bialonczyk 210e3af95e6SMariusz Bialonczyk mutex_unlock(&sl->master->bus_mutex); 211e3af95e6SMariusz Bialonczyk sleep_rem = msleep_interruptible(tm); 212e3af95e6SMariusz Bialonczyk if (sleep_rem != 0) { 213e3af95e6SMariusz Bialonczyk ret = -1; 214e3af95e6SMariusz Bialonczyk goto post_unlock; 215e3af95e6SMariusz Bialonczyk } 216e3af95e6SMariusz Bialonczyk 217e3af95e6SMariusz Bialonczyk if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) { 218e3af95e6SMariusz Bialonczyk ret = -1; 219e3af95e6SMariusz Bialonczyk goto post_unlock; 220e3af95e6SMariusz Bialonczyk } 221e3af95e6SMariusz Bialonczyk 222e3af95e6SMariusz Bialonczyk break; 223e3af95e6SMariusz Bialonczyk } 224e3af95e6SMariusz Bialonczyk 225e3af95e6SMariusz Bialonczyk if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { 226e3af95e6SMariusz Bialonczyk *voltage = (((uint16_t) w1_buf[DS2438_VOLTAGE_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_VOLTAGE_LSB]); 227e3af95e6SMariusz Bialonczyk ret = 0; 228e3af95e6SMariusz Bialonczyk } else 229e3af95e6SMariusz Bialonczyk ret = -1; 230e3af95e6SMariusz Bialonczyk 231e3af95e6SMariusz Bialonczyk pre_unlock: 232e3af95e6SMariusz Bialonczyk mutex_unlock(&sl->master->bus_mutex); 233e3af95e6SMariusz Bialonczyk 234e3af95e6SMariusz Bialonczyk post_unlock: 235e3af95e6SMariusz Bialonczyk return ret; 236e3af95e6SMariusz Bialonczyk } 237e3af95e6SMariusz Bialonczyk 238*6eaafbb6SJulien Folly static int w1_ds2438_get_current(struct w1_slave *sl, int16_t *voltage) 239*6eaafbb6SJulien Folly { 240*6eaafbb6SJulien Folly u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; 241*6eaafbb6SJulien Folly int ret; 242*6eaafbb6SJulien Folly 243*6eaafbb6SJulien Folly mutex_lock(&sl->master->bus_mutex); 244*6eaafbb6SJulien Folly 245*6eaafbb6SJulien Folly if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { 246*6eaafbb6SJulien Folly /* The voltage measured across current sense resistor RSENS. */ 247*6eaafbb6SJulien Folly *voltage = (((int16_t) w1_buf[DS2438_CURRENT_MSB]) << 8) | ((int16_t) w1_buf[DS2438_CURRENT_LSB]); 248*6eaafbb6SJulien Folly ret = 0; 249*6eaafbb6SJulien Folly } else 250*6eaafbb6SJulien Folly ret = -1; 251*6eaafbb6SJulien Folly 252*6eaafbb6SJulien Folly mutex_unlock(&sl->master->bus_mutex); 253*6eaafbb6SJulien Folly 254*6eaafbb6SJulien Folly return ret; 255*6eaafbb6SJulien Folly } 256*6eaafbb6SJulien Folly 257e3af95e6SMariusz Bialonczyk static ssize_t iad_write(struct file *filp, struct kobject *kobj, 258e3af95e6SMariusz Bialonczyk struct bin_attribute *bin_attr, char *buf, 259e3af95e6SMariusz Bialonczyk loff_t off, size_t count) 260e3af95e6SMariusz Bialonczyk { 261e3af95e6SMariusz Bialonczyk struct w1_slave *sl = kobj_to_w1_slave(kobj); 262e3af95e6SMariusz Bialonczyk int ret; 263e3af95e6SMariusz Bialonczyk 264e3af95e6SMariusz Bialonczyk if (count != 1 || off != 0) 265e3af95e6SMariusz Bialonczyk return -EFAULT; 266e3af95e6SMariusz Bialonczyk 267e3af95e6SMariusz Bialonczyk mutex_lock(&sl->master->bus_mutex); 268e3af95e6SMariusz Bialonczyk 269e3af95e6SMariusz Bialonczyk if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_IAD, *buf & 0x01) == 0) 270e3af95e6SMariusz Bialonczyk ret = 1; 271e3af95e6SMariusz Bialonczyk else 272e3af95e6SMariusz Bialonczyk ret = -EIO; 273e3af95e6SMariusz Bialonczyk 274e3af95e6SMariusz Bialonczyk mutex_unlock(&sl->master->bus_mutex); 275e3af95e6SMariusz Bialonczyk 276e3af95e6SMariusz Bialonczyk return ret; 277e3af95e6SMariusz Bialonczyk } 278e3af95e6SMariusz Bialonczyk 279*6eaafbb6SJulien Folly static ssize_t iad_read(struct file *filp, struct kobject *kobj, 280*6eaafbb6SJulien Folly struct bin_attribute *bin_attr, char *buf, 281*6eaafbb6SJulien Folly loff_t off, size_t count) 282*6eaafbb6SJulien Folly { 283*6eaafbb6SJulien Folly struct w1_slave *sl = kobj_to_w1_slave(kobj); 284*6eaafbb6SJulien Folly int ret; 285*6eaafbb6SJulien Folly int16_t voltage; 286*6eaafbb6SJulien Folly 287*6eaafbb6SJulien Folly if (off != 0) 288*6eaafbb6SJulien Folly return 0; 289*6eaafbb6SJulien Folly if (!buf) 290*6eaafbb6SJulien Folly return -EINVAL; 291*6eaafbb6SJulien Folly 292*6eaafbb6SJulien Folly if (w1_ds2438_get_current(sl, &voltage) == 0) { 293*6eaafbb6SJulien Folly ret = snprintf(buf, count, "%i\n", voltage); 294*6eaafbb6SJulien Folly } else 295*6eaafbb6SJulien Folly ret = -EIO; 296*6eaafbb6SJulien Folly 297*6eaafbb6SJulien Folly return ret; 298*6eaafbb6SJulien Folly } 299*6eaafbb6SJulien Folly 300e3af95e6SMariusz Bialonczyk static ssize_t page0_read(struct file *filp, struct kobject *kobj, 301e3af95e6SMariusz Bialonczyk struct bin_attribute *bin_attr, char *buf, 302e3af95e6SMariusz Bialonczyk loff_t off, size_t count) 303e3af95e6SMariusz Bialonczyk { 304e3af95e6SMariusz Bialonczyk struct w1_slave *sl = kobj_to_w1_slave(kobj); 305e3af95e6SMariusz Bialonczyk int ret; 306e3af95e6SMariusz Bialonczyk u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; 307e3af95e6SMariusz Bialonczyk 308e3af95e6SMariusz Bialonczyk if (off != 0) 309e3af95e6SMariusz Bialonczyk return 0; 310e3af95e6SMariusz Bialonczyk if (!buf) 311e3af95e6SMariusz Bialonczyk return -EINVAL; 312e3af95e6SMariusz Bialonczyk 313e3af95e6SMariusz Bialonczyk mutex_lock(&sl->master->bus_mutex); 314e3af95e6SMariusz Bialonczyk 315*6eaafbb6SJulien Folly /* Read no more than page0 size */ 316*6eaafbb6SJulien Folly if (count > DS2438_PAGE_SIZE) 317*6eaafbb6SJulien Folly count = DS2438_PAGE_SIZE; 318*6eaafbb6SJulien Folly 319e3af95e6SMariusz Bialonczyk if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { 320*6eaafbb6SJulien Folly memcpy(buf, &w1_buf, count); 321*6eaafbb6SJulien Folly ret = count; 322e3af95e6SMariusz Bialonczyk } else 323e3af95e6SMariusz Bialonczyk ret = -EIO; 324e3af95e6SMariusz Bialonczyk 325e3af95e6SMariusz Bialonczyk mutex_unlock(&sl->master->bus_mutex); 326e3af95e6SMariusz Bialonczyk 327e3af95e6SMariusz Bialonczyk return ret; 328e3af95e6SMariusz Bialonczyk } 329e3af95e6SMariusz Bialonczyk 330e3af95e6SMariusz Bialonczyk static ssize_t temperature_read(struct file *filp, struct kobject *kobj, 331e3af95e6SMariusz Bialonczyk struct bin_attribute *bin_attr, char *buf, 332e3af95e6SMariusz Bialonczyk loff_t off, size_t count) 333e3af95e6SMariusz Bialonczyk { 334e3af95e6SMariusz Bialonczyk struct w1_slave *sl = kobj_to_w1_slave(kobj); 335e3af95e6SMariusz Bialonczyk int ret; 336e3af95e6SMariusz Bialonczyk int16_t temp; 337e3af95e6SMariusz Bialonczyk 338e3af95e6SMariusz Bialonczyk if (off != 0) 339e3af95e6SMariusz Bialonczyk return 0; 340e3af95e6SMariusz Bialonczyk if (!buf) 341e3af95e6SMariusz Bialonczyk return -EINVAL; 342e3af95e6SMariusz Bialonczyk 343e3af95e6SMariusz Bialonczyk if (w1_ds2438_get_temperature(sl, &temp) == 0) { 344*6eaafbb6SJulien Folly ret = snprintf(buf, count, "%i\n", temp); 345e3af95e6SMariusz Bialonczyk } else 346e3af95e6SMariusz Bialonczyk ret = -EIO; 347e3af95e6SMariusz Bialonczyk 348e3af95e6SMariusz Bialonczyk return ret; 349e3af95e6SMariusz Bialonczyk } 350e3af95e6SMariusz Bialonczyk 351e3af95e6SMariusz Bialonczyk static ssize_t vad_read(struct file *filp, struct kobject *kobj, 352e3af95e6SMariusz Bialonczyk struct bin_attribute *bin_attr, char *buf, 353e3af95e6SMariusz Bialonczyk loff_t off, size_t count) 354e3af95e6SMariusz Bialonczyk { 355e3af95e6SMariusz Bialonczyk struct w1_slave *sl = kobj_to_w1_slave(kobj); 356e3af95e6SMariusz Bialonczyk int ret; 357e3af95e6SMariusz Bialonczyk uint16_t voltage; 358e3af95e6SMariusz Bialonczyk 359e3af95e6SMariusz Bialonczyk if (off != 0) 360e3af95e6SMariusz Bialonczyk return 0; 361e3af95e6SMariusz Bialonczyk if (!buf) 362e3af95e6SMariusz Bialonczyk return -EINVAL; 363e3af95e6SMariusz Bialonczyk 364e3af95e6SMariusz Bialonczyk if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0) { 365*6eaafbb6SJulien Folly ret = snprintf(buf, count, "%u\n", voltage); 366e3af95e6SMariusz Bialonczyk } else 367e3af95e6SMariusz Bialonczyk ret = -EIO; 368e3af95e6SMariusz Bialonczyk 369e3af95e6SMariusz Bialonczyk return ret; 370e3af95e6SMariusz Bialonczyk } 371e3af95e6SMariusz Bialonczyk 372e3af95e6SMariusz Bialonczyk static ssize_t vdd_read(struct file *filp, struct kobject *kobj, 373e3af95e6SMariusz Bialonczyk struct bin_attribute *bin_attr, char *buf, 374e3af95e6SMariusz Bialonczyk loff_t off, size_t count) 375e3af95e6SMariusz Bialonczyk { 376e3af95e6SMariusz Bialonczyk struct w1_slave *sl = kobj_to_w1_slave(kobj); 377e3af95e6SMariusz Bialonczyk int ret; 378e3af95e6SMariusz Bialonczyk uint16_t voltage; 379e3af95e6SMariusz Bialonczyk 380e3af95e6SMariusz Bialonczyk if (off != 0) 381e3af95e6SMariusz Bialonczyk return 0; 382e3af95e6SMariusz Bialonczyk if (!buf) 383e3af95e6SMariusz Bialonczyk return -EINVAL; 384e3af95e6SMariusz Bialonczyk 385e3af95e6SMariusz Bialonczyk if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0) { 386*6eaafbb6SJulien Folly ret = snprintf(buf, count, "%u\n", voltage); 387e3af95e6SMariusz Bialonczyk } else 388e3af95e6SMariusz Bialonczyk ret = -EIO; 389e3af95e6SMariusz Bialonczyk 390e3af95e6SMariusz Bialonczyk return ret; 391e3af95e6SMariusz Bialonczyk } 392e3af95e6SMariusz Bialonczyk 393*6eaafbb6SJulien Folly static BIN_ATTR(iad, S_IRUGO | S_IWUSR | S_IWGRP, iad_read, iad_write, 0); 394e3af95e6SMariusz Bialonczyk static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE); 395e3af95e6SMariusz Bialonczyk static BIN_ATTR_RO(temperature, 0/* real length varies */); 396e3af95e6SMariusz Bialonczyk static BIN_ATTR_RO(vad, 0/* real length varies */); 397e3af95e6SMariusz Bialonczyk static BIN_ATTR_RO(vdd, 0/* real length varies */); 398e3af95e6SMariusz Bialonczyk 399e3af95e6SMariusz Bialonczyk static struct bin_attribute *w1_ds2438_bin_attrs[] = { 400e3af95e6SMariusz Bialonczyk &bin_attr_iad, 401e3af95e6SMariusz Bialonczyk &bin_attr_page0, 402e3af95e6SMariusz Bialonczyk &bin_attr_temperature, 403e3af95e6SMariusz Bialonczyk &bin_attr_vad, 404e3af95e6SMariusz Bialonczyk &bin_attr_vdd, 405e3af95e6SMariusz Bialonczyk NULL, 406e3af95e6SMariusz Bialonczyk }; 407e3af95e6SMariusz Bialonczyk 408e3af95e6SMariusz Bialonczyk static const struct attribute_group w1_ds2438_group = { 409e3af95e6SMariusz Bialonczyk .bin_attrs = w1_ds2438_bin_attrs, 410e3af95e6SMariusz Bialonczyk }; 411e3af95e6SMariusz Bialonczyk 412e3af95e6SMariusz Bialonczyk static const struct attribute_group *w1_ds2438_groups[] = { 413e3af95e6SMariusz Bialonczyk &w1_ds2438_group, 414e3af95e6SMariusz Bialonczyk NULL, 415e3af95e6SMariusz Bialonczyk }; 416e3af95e6SMariusz Bialonczyk 417e3af95e6SMariusz Bialonczyk static struct w1_family_ops w1_ds2438_fops = { 418e3af95e6SMariusz Bialonczyk .groups = w1_ds2438_groups, 419e3af95e6SMariusz Bialonczyk }; 420e3af95e6SMariusz Bialonczyk 421e3af95e6SMariusz Bialonczyk static struct w1_family w1_ds2438_family = { 422e3af95e6SMariusz Bialonczyk .fid = W1_FAMILY_DS2438, 423e3af95e6SMariusz Bialonczyk .fops = &w1_ds2438_fops, 424e3af95e6SMariusz Bialonczyk }; 425e3af95e6SMariusz Bialonczyk module_w1_family(w1_ds2438_family); 426e3af95e6SMariusz Bialonczyk 427e3af95e6SMariusz Bialonczyk MODULE_LICENSE("GPL"); 428e3af95e6SMariusz Bialonczyk MODULE_AUTHOR("Mariusz Bialonczyk <manio@skyboo.net>"); 429e3af95e6SMariusz Bialonczyk MODULE_DESCRIPTION("1-wire driver for Maxim/Dallas DS2438 Smart Battery Monitor"); 430e3af95e6SMariusz Bialonczyk MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2438)); 431