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 54*e5cf84e8SColin 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 88*e5cf84e8SColin 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 130*e5cf84e8SColin 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*e5cf84e8SColin Ian King static uint16_t w1_ds2438_get_voltage(struct w1_slave *sl, 190*e5cf84e8SColin 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 238e3af95e6SMariusz Bialonczyk static ssize_t iad_write(struct file *filp, struct kobject *kobj, 239e3af95e6SMariusz Bialonczyk struct bin_attribute *bin_attr, char *buf, 240e3af95e6SMariusz Bialonczyk loff_t off, size_t count) 241e3af95e6SMariusz Bialonczyk { 242e3af95e6SMariusz Bialonczyk struct w1_slave *sl = kobj_to_w1_slave(kobj); 243e3af95e6SMariusz Bialonczyk int ret; 244e3af95e6SMariusz Bialonczyk 245e3af95e6SMariusz Bialonczyk if (count != 1 || off != 0) 246e3af95e6SMariusz Bialonczyk return -EFAULT; 247e3af95e6SMariusz Bialonczyk 248e3af95e6SMariusz Bialonczyk mutex_lock(&sl->master->bus_mutex); 249e3af95e6SMariusz Bialonczyk 250e3af95e6SMariusz Bialonczyk if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_IAD, *buf & 0x01) == 0) 251e3af95e6SMariusz Bialonczyk ret = 1; 252e3af95e6SMariusz Bialonczyk else 253e3af95e6SMariusz Bialonczyk ret = -EIO; 254e3af95e6SMariusz Bialonczyk 255e3af95e6SMariusz Bialonczyk mutex_unlock(&sl->master->bus_mutex); 256e3af95e6SMariusz Bialonczyk 257e3af95e6SMariusz Bialonczyk return ret; 258e3af95e6SMariusz Bialonczyk } 259e3af95e6SMariusz Bialonczyk 260e3af95e6SMariusz Bialonczyk static ssize_t page0_read(struct file *filp, struct kobject *kobj, 261e3af95e6SMariusz Bialonczyk struct bin_attribute *bin_attr, char *buf, 262e3af95e6SMariusz Bialonczyk loff_t off, size_t count) 263e3af95e6SMariusz Bialonczyk { 264e3af95e6SMariusz Bialonczyk struct w1_slave *sl = kobj_to_w1_slave(kobj); 265e3af95e6SMariusz Bialonczyk int ret; 266e3af95e6SMariusz Bialonczyk u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; 267e3af95e6SMariusz Bialonczyk 268e3af95e6SMariusz Bialonczyk if (off != 0) 269e3af95e6SMariusz Bialonczyk return 0; 270e3af95e6SMariusz Bialonczyk if (!buf) 271e3af95e6SMariusz Bialonczyk return -EINVAL; 272e3af95e6SMariusz Bialonczyk 273e3af95e6SMariusz Bialonczyk mutex_lock(&sl->master->bus_mutex); 274e3af95e6SMariusz Bialonczyk 275e3af95e6SMariusz Bialonczyk if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { 276e3af95e6SMariusz Bialonczyk memcpy(buf, &w1_buf, DS2438_PAGE_SIZE); 277e3af95e6SMariusz Bialonczyk ret = DS2438_PAGE_SIZE; 278e3af95e6SMariusz Bialonczyk } else 279e3af95e6SMariusz Bialonczyk ret = -EIO; 280e3af95e6SMariusz Bialonczyk 281e3af95e6SMariusz Bialonczyk mutex_unlock(&sl->master->bus_mutex); 282e3af95e6SMariusz Bialonczyk 283e3af95e6SMariusz Bialonczyk return ret; 284e3af95e6SMariusz Bialonczyk } 285e3af95e6SMariusz Bialonczyk 286e3af95e6SMariusz Bialonczyk static ssize_t temperature_read(struct file *filp, struct kobject *kobj, 287e3af95e6SMariusz Bialonczyk struct bin_attribute *bin_attr, char *buf, 288e3af95e6SMariusz Bialonczyk loff_t off, size_t count) 289e3af95e6SMariusz Bialonczyk { 290e3af95e6SMariusz Bialonczyk struct w1_slave *sl = kobj_to_w1_slave(kobj); 291e3af95e6SMariusz Bialonczyk int ret; 292e3af95e6SMariusz Bialonczyk ssize_t c = PAGE_SIZE; 293e3af95e6SMariusz Bialonczyk int16_t temp; 294e3af95e6SMariusz Bialonczyk 295e3af95e6SMariusz Bialonczyk if (off != 0) 296e3af95e6SMariusz Bialonczyk return 0; 297e3af95e6SMariusz Bialonczyk if (!buf) 298e3af95e6SMariusz Bialonczyk return -EINVAL; 299e3af95e6SMariusz Bialonczyk 300e3af95e6SMariusz Bialonczyk if (w1_ds2438_get_temperature(sl, &temp) == 0) { 301e3af95e6SMariusz Bialonczyk c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", temp); 302e3af95e6SMariusz Bialonczyk ret = PAGE_SIZE - c; 303e3af95e6SMariusz Bialonczyk } else 304e3af95e6SMariusz Bialonczyk ret = -EIO; 305e3af95e6SMariusz Bialonczyk 306e3af95e6SMariusz Bialonczyk return ret; 307e3af95e6SMariusz Bialonczyk } 308e3af95e6SMariusz Bialonczyk 309e3af95e6SMariusz Bialonczyk static ssize_t vad_read(struct file *filp, struct kobject *kobj, 310e3af95e6SMariusz Bialonczyk struct bin_attribute *bin_attr, char *buf, 311e3af95e6SMariusz Bialonczyk loff_t off, size_t count) 312e3af95e6SMariusz Bialonczyk { 313e3af95e6SMariusz Bialonczyk struct w1_slave *sl = kobj_to_w1_slave(kobj); 314e3af95e6SMariusz Bialonczyk int ret; 315e3af95e6SMariusz Bialonczyk ssize_t c = PAGE_SIZE; 316e3af95e6SMariusz Bialonczyk uint16_t voltage; 317e3af95e6SMariusz Bialonczyk 318e3af95e6SMariusz Bialonczyk if (off != 0) 319e3af95e6SMariusz Bialonczyk return 0; 320e3af95e6SMariusz Bialonczyk if (!buf) 321e3af95e6SMariusz Bialonczyk return -EINVAL; 322e3af95e6SMariusz Bialonczyk 323e3af95e6SMariusz Bialonczyk if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0) { 324e3af95e6SMariusz Bialonczyk c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", voltage); 325e3af95e6SMariusz Bialonczyk ret = PAGE_SIZE - c; 326e3af95e6SMariusz Bialonczyk } else 327e3af95e6SMariusz Bialonczyk ret = -EIO; 328e3af95e6SMariusz Bialonczyk 329e3af95e6SMariusz Bialonczyk return ret; 330e3af95e6SMariusz Bialonczyk } 331e3af95e6SMariusz Bialonczyk 332e3af95e6SMariusz Bialonczyk static ssize_t vdd_read(struct file *filp, struct kobject *kobj, 333e3af95e6SMariusz Bialonczyk struct bin_attribute *bin_attr, char *buf, 334e3af95e6SMariusz Bialonczyk loff_t off, size_t count) 335e3af95e6SMariusz Bialonczyk { 336e3af95e6SMariusz Bialonczyk struct w1_slave *sl = kobj_to_w1_slave(kobj); 337e3af95e6SMariusz Bialonczyk int ret; 338e3af95e6SMariusz Bialonczyk ssize_t c = PAGE_SIZE; 339e3af95e6SMariusz Bialonczyk uint16_t voltage; 340e3af95e6SMariusz Bialonczyk 341e3af95e6SMariusz Bialonczyk if (off != 0) 342e3af95e6SMariusz Bialonczyk return 0; 343e3af95e6SMariusz Bialonczyk if (!buf) 344e3af95e6SMariusz Bialonczyk return -EINVAL; 345e3af95e6SMariusz Bialonczyk 346e3af95e6SMariusz Bialonczyk if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0) { 347e3af95e6SMariusz Bialonczyk c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", voltage); 348e3af95e6SMariusz Bialonczyk ret = PAGE_SIZE - c; 349e3af95e6SMariusz Bialonczyk } else 350e3af95e6SMariusz Bialonczyk ret = -EIO; 351e3af95e6SMariusz Bialonczyk 352e3af95e6SMariusz Bialonczyk return ret; 353e3af95e6SMariusz Bialonczyk } 354e3af95e6SMariusz Bialonczyk 355e3af95e6SMariusz Bialonczyk static BIN_ATTR(iad, S_IRUGO | S_IWUSR | S_IWGRP, NULL, iad_write, 1); 356e3af95e6SMariusz Bialonczyk static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE); 357e3af95e6SMariusz Bialonczyk static BIN_ATTR_RO(temperature, 0/* real length varies */); 358e3af95e6SMariusz Bialonczyk static BIN_ATTR_RO(vad, 0/* real length varies */); 359e3af95e6SMariusz Bialonczyk static BIN_ATTR_RO(vdd, 0/* real length varies */); 360e3af95e6SMariusz Bialonczyk 361e3af95e6SMariusz Bialonczyk static struct bin_attribute *w1_ds2438_bin_attrs[] = { 362e3af95e6SMariusz Bialonczyk &bin_attr_iad, 363e3af95e6SMariusz Bialonczyk &bin_attr_page0, 364e3af95e6SMariusz Bialonczyk &bin_attr_temperature, 365e3af95e6SMariusz Bialonczyk &bin_attr_vad, 366e3af95e6SMariusz Bialonczyk &bin_attr_vdd, 367e3af95e6SMariusz Bialonczyk NULL, 368e3af95e6SMariusz Bialonczyk }; 369e3af95e6SMariusz Bialonczyk 370e3af95e6SMariusz Bialonczyk static const struct attribute_group w1_ds2438_group = { 371e3af95e6SMariusz Bialonczyk .bin_attrs = w1_ds2438_bin_attrs, 372e3af95e6SMariusz Bialonczyk }; 373e3af95e6SMariusz Bialonczyk 374e3af95e6SMariusz Bialonczyk static const struct attribute_group *w1_ds2438_groups[] = { 375e3af95e6SMariusz Bialonczyk &w1_ds2438_group, 376e3af95e6SMariusz Bialonczyk NULL, 377e3af95e6SMariusz Bialonczyk }; 378e3af95e6SMariusz Bialonczyk 379e3af95e6SMariusz Bialonczyk static struct w1_family_ops w1_ds2438_fops = { 380e3af95e6SMariusz Bialonczyk .groups = w1_ds2438_groups, 381e3af95e6SMariusz Bialonczyk }; 382e3af95e6SMariusz Bialonczyk 383e3af95e6SMariusz Bialonczyk static struct w1_family w1_ds2438_family = { 384e3af95e6SMariusz Bialonczyk .fid = W1_FAMILY_DS2438, 385e3af95e6SMariusz Bialonczyk .fops = &w1_ds2438_fops, 386e3af95e6SMariusz Bialonczyk }; 387e3af95e6SMariusz Bialonczyk module_w1_family(w1_ds2438_family); 388e3af95e6SMariusz Bialonczyk 389e3af95e6SMariusz Bialonczyk MODULE_LICENSE("GPL"); 390e3af95e6SMariusz Bialonczyk MODULE_AUTHOR("Mariusz Bialonczyk <manio@skyboo.net>"); 391e3af95e6SMariusz Bialonczyk MODULE_DESCRIPTION("1-wire driver for Maxim/Dallas DS2438 Smart Battery Monitor"); 392e3af95e6SMariusz Bialonczyk MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2438)); 393