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