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