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 /* Page #1 definitions */ 53 #define DS2438_ETM_0 0x00 54 #define DS2438_ETM_1 0x01 55 #define DS2438_ETM_2 0x02 56 #define DS2438_ETM_3 0x03 57 #define DS2438_ICA 0x04 58 #define DS2438_OFFSET_LSB 0x05 59 #define DS2438_OFFSET_MSB 0x06 60 61 static int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf) 62 { 63 unsigned int retries = W1_DS2438_RETRIES; 64 u8 w1_buf[2]; 65 u8 crc; 66 size_t count; 67 68 while (retries--) { 69 crc = 0; 70 71 if (w1_reset_select_slave(sl)) 72 continue; 73 w1_buf[0] = W1_DS2438_RECALL_MEMORY; 74 w1_buf[1] = (u8)pageno; 75 w1_write_block(sl->master, w1_buf, 2); 76 77 if (w1_reset_select_slave(sl)) 78 continue; 79 w1_buf[0] = W1_DS2438_READ_SCRATCH; 80 w1_buf[1] = (u8)pageno; 81 w1_write_block(sl->master, w1_buf, 2); 82 83 count = w1_read_block(sl->master, buf, DS2438_PAGE_SIZE + 1); 84 if (count == DS2438_PAGE_SIZE + 1) { 85 crc = w1_calc_crc8(buf, DS2438_PAGE_SIZE); 86 87 /* check for correct CRC */ 88 if ((u8)buf[DS2438_PAGE_SIZE] == crc) 89 return 0; 90 } 91 } 92 return -1; 93 } 94 95 static int w1_ds2438_get_temperature(struct w1_slave *sl, int16_t *temperature) 96 { 97 unsigned int retries = W1_DS2438_RETRIES; 98 u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; 99 unsigned int tm = DS2438_MAX_CONVERSION_TIME; 100 unsigned long sleep_rem; 101 int ret; 102 103 mutex_lock(&sl->master->bus_mutex); 104 105 while (retries--) { 106 if (w1_reset_select_slave(sl)) 107 continue; 108 w1_write_8(sl->master, W1_DS2438_CONVERT_TEMP); 109 110 mutex_unlock(&sl->master->bus_mutex); 111 sleep_rem = msleep_interruptible(tm); 112 if (sleep_rem != 0) { 113 ret = -1; 114 goto post_unlock; 115 } 116 117 if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) { 118 ret = -1; 119 goto post_unlock; 120 } 121 122 break; 123 } 124 125 if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { 126 *temperature = (((int16_t) w1_buf[DS2438_TEMP_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_TEMP_LSB]); 127 ret = 0; 128 } else 129 ret = -1; 130 131 mutex_unlock(&sl->master->bus_mutex); 132 133 post_unlock: 134 return ret; 135 } 136 137 static int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value) 138 { 139 unsigned int retries = W1_DS2438_RETRIES; 140 u8 w1_buf[3]; 141 u8 status; 142 int perform_write = 0; 143 144 while (retries--) { 145 if (w1_reset_select_slave(sl)) 146 continue; 147 w1_buf[0] = W1_DS2438_RECALL_MEMORY; 148 w1_buf[1] = 0x00; 149 w1_write_block(sl->master, w1_buf, 2); 150 151 if (w1_reset_select_slave(sl)) 152 continue; 153 w1_buf[0] = W1_DS2438_READ_SCRATCH; 154 w1_buf[1] = 0x00; 155 w1_write_block(sl->master, w1_buf, 2); 156 157 /* reading one byte of result */ 158 status = w1_read_8(sl->master); 159 160 /* if bit0=1, set a value to a mask for easy compare */ 161 if (value) 162 value = mask; 163 164 if ((status & mask) == value) 165 return 0; /* already set as requested */ 166 167 /* changing bit */ 168 status ^= mask; 169 perform_write = 1; 170 171 break; 172 } 173 174 if (perform_write) { 175 retries = W1_DS2438_RETRIES; 176 while (retries--) { 177 if (w1_reset_select_slave(sl)) 178 continue; 179 w1_buf[0] = W1_DS2438_WRITE_SCRATCH; 180 w1_buf[1] = 0x00; 181 w1_buf[2] = status; 182 w1_write_block(sl->master, w1_buf, 3); 183 184 if (w1_reset_select_slave(sl)) 185 continue; 186 w1_buf[0] = W1_DS2438_COPY_SCRATCH; 187 w1_buf[1] = 0x00; 188 w1_write_block(sl->master, w1_buf, 2); 189 190 return 0; 191 } 192 } 193 return -1; 194 } 195 196 static int w1_ds2438_change_offset_register(struct w1_slave *sl, u8 *value) 197 { 198 unsigned int retries = W1_DS2438_RETRIES; 199 u8 w1_buf[9]; 200 u8 w1_page1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; 201 202 if (w1_ds2438_get_page(sl, 1, w1_page1_buf) == 0) { 203 memcpy(&w1_buf[2], w1_page1_buf, DS2438_PAGE_SIZE - 1); /* last register reserved */ 204 w1_buf[7] = value[0]; /* change only offset register */ 205 w1_buf[8] = value[1]; 206 while (retries--) { 207 if (w1_reset_select_slave(sl)) 208 continue; 209 w1_buf[0] = W1_DS2438_WRITE_SCRATCH; 210 w1_buf[1] = 0x01; /* write to page 1 */ 211 w1_write_block(sl->master, w1_buf, 9); 212 213 if (w1_reset_select_slave(sl)) 214 continue; 215 w1_buf[0] = W1_DS2438_COPY_SCRATCH; 216 w1_buf[1] = 0x01; 217 w1_write_block(sl->master, w1_buf, 2); 218 return 0; 219 } 220 } 221 return -1; 222 } 223 224 static int w1_ds2438_get_voltage(struct w1_slave *sl, 225 int adc_input, uint16_t *voltage) 226 { 227 unsigned int retries = W1_DS2438_RETRIES; 228 u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; 229 unsigned int tm = DS2438_MAX_CONVERSION_TIME; 230 unsigned long sleep_rem; 231 int ret; 232 233 mutex_lock(&sl->master->bus_mutex); 234 235 if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_AD, adc_input)) { 236 ret = -1; 237 goto pre_unlock; 238 } 239 240 while (retries--) { 241 if (w1_reset_select_slave(sl)) 242 continue; 243 w1_write_8(sl->master, W1_DS2438_CONVERT_VOLTAGE); 244 245 mutex_unlock(&sl->master->bus_mutex); 246 sleep_rem = msleep_interruptible(tm); 247 if (sleep_rem != 0) { 248 ret = -1; 249 goto post_unlock; 250 } 251 252 if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) { 253 ret = -1; 254 goto post_unlock; 255 } 256 257 break; 258 } 259 260 if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { 261 *voltage = (((uint16_t) w1_buf[DS2438_VOLTAGE_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_VOLTAGE_LSB]); 262 ret = 0; 263 } else 264 ret = -1; 265 266 pre_unlock: 267 mutex_unlock(&sl->master->bus_mutex); 268 269 post_unlock: 270 return ret; 271 } 272 273 static int w1_ds2438_get_current(struct w1_slave *sl, int16_t *voltage) 274 { 275 u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; 276 int ret; 277 278 mutex_lock(&sl->master->bus_mutex); 279 280 if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { 281 /* The voltage measured across current sense resistor RSENS. */ 282 *voltage = (((int16_t) w1_buf[DS2438_CURRENT_MSB]) << 8) | ((int16_t) w1_buf[DS2438_CURRENT_LSB]); 283 ret = 0; 284 } else 285 ret = -1; 286 287 mutex_unlock(&sl->master->bus_mutex); 288 289 return ret; 290 } 291 292 static ssize_t iad_write(struct file *filp, struct kobject *kobj, 293 struct bin_attribute *bin_attr, char *buf, 294 loff_t off, size_t count) 295 { 296 struct w1_slave *sl = kobj_to_w1_slave(kobj); 297 int ret; 298 299 if (count != 1 || off != 0) 300 return -EFAULT; 301 302 mutex_lock(&sl->master->bus_mutex); 303 304 if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_IAD, *buf & 0x01) == 0) 305 ret = 1; 306 else 307 ret = -EIO; 308 309 mutex_unlock(&sl->master->bus_mutex); 310 311 return ret; 312 } 313 314 static ssize_t iad_read(struct file *filp, struct kobject *kobj, 315 struct bin_attribute *bin_attr, char *buf, 316 loff_t off, size_t count) 317 { 318 struct w1_slave *sl = kobj_to_w1_slave(kobj); 319 int ret; 320 int16_t voltage; 321 322 if (off != 0) 323 return 0; 324 if (!buf) 325 return -EINVAL; 326 327 if (w1_ds2438_get_current(sl, &voltage) == 0) 328 ret = snprintf(buf, count, "%i\n", voltage); 329 else 330 ret = -EIO; 331 332 return ret; 333 } 334 335 static ssize_t page0_read(struct file *filp, struct kobject *kobj, 336 struct bin_attribute *bin_attr, char *buf, 337 loff_t off, size_t count) 338 { 339 struct w1_slave *sl = kobj_to_w1_slave(kobj); 340 int ret; 341 u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; 342 343 if (off != 0) 344 return 0; 345 if (!buf) 346 return -EINVAL; 347 348 mutex_lock(&sl->master->bus_mutex); 349 350 /* Read no more than page0 size */ 351 if (count > DS2438_PAGE_SIZE) 352 count = DS2438_PAGE_SIZE; 353 354 if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { 355 memcpy(buf, &w1_buf, count); 356 ret = count; 357 } else 358 ret = -EIO; 359 360 mutex_unlock(&sl->master->bus_mutex); 361 362 return ret; 363 } 364 365 static ssize_t page1_read(struct file *filp, struct kobject *kobj, 366 struct bin_attribute *bin_attr, char *buf, 367 loff_t off, size_t count) 368 { 369 struct w1_slave *sl = kobj_to_w1_slave(kobj); 370 int ret; 371 u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; 372 373 if (off != 0) 374 return 0; 375 if (!buf) 376 return -EINVAL; 377 378 mutex_lock(&sl->master->bus_mutex); 379 380 /* Read no more than page1 size */ 381 if (count > DS2438_PAGE_SIZE) 382 count = DS2438_PAGE_SIZE; 383 384 if (w1_ds2438_get_page(sl, 1, w1_buf) == 0) { 385 memcpy(buf, &w1_buf, count); 386 ret = count; 387 } else 388 ret = -EIO; 389 390 mutex_unlock(&sl->master->bus_mutex); 391 392 return ret; 393 } 394 395 static ssize_t offset_write(struct file *filp, struct kobject *kobj, 396 struct bin_attribute *bin_attr, char *buf, 397 loff_t off, size_t count) 398 { 399 struct w1_slave *sl = kobj_to_w1_slave(kobj); 400 int ret; 401 402 mutex_lock(&sl->master->bus_mutex); 403 404 if (w1_ds2438_change_offset_register(sl, buf) == 0) 405 ret = count; 406 else 407 ret = -EIO; 408 409 mutex_unlock(&sl->master->bus_mutex); 410 411 return ret; 412 } 413 414 static ssize_t temperature_read(struct file *filp, struct kobject *kobj, 415 struct bin_attribute *bin_attr, char *buf, 416 loff_t off, size_t count) 417 { 418 struct w1_slave *sl = kobj_to_w1_slave(kobj); 419 int ret; 420 int16_t temp; 421 422 if (off != 0) 423 return 0; 424 if (!buf) 425 return -EINVAL; 426 427 if (w1_ds2438_get_temperature(sl, &temp) == 0) 428 ret = snprintf(buf, count, "%i\n", temp); 429 else 430 ret = -EIO; 431 432 return ret; 433 } 434 435 static ssize_t vad_read(struct file *filp, struct kobject *kobj, 436 struct bin_attribute *bin_attr, char *buf, 437 loff_t off, size_t count) 438 { 439 struct w1_slave *sl = kobj_to_w1_slave(kobj); 440 int ret; 441 uint16_t voltage; 442 443 if (off != 0) 444 return 0; 445 if (!buf) 446 return -EINVAL; 447 448 if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0) 449 ret = snprintf(buf, count, "%u\n", voltage); 450 else 451 ret = -EIO; 452 453 return ret; 454 } 455 456 static ssize_t vdd_read(struct file *filp, struct kobject *kobj, 457 struct bin_attribute *bin_attr, char *buf, 458 loff_t off, size_t count) 459 { 460 struct w1_slave *sl = kobj_to_w1_slave(kobj); 461 int ret; 462 uint16_t voltage; 463 464 if (off != 0) 465 return 0; 466 if (!buf) 467 return -EINVAL; 468 469 if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0) 470 ret = snprintf(buf, count, "%u\n", voltage); 471 else 472 ret = -EIO; 473 474 return ret; 475 } 476 477 static BIN_ATTR_RW(iad, 0); 478 static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE); 479 static BIN_ATTR_RO(page1, DS2438_PAGE_SIZE); 480 static BIN_ATTR_WO(offset, 2); 481 static BIN_ATTR_RO(temperature, 0/* real length varies */); 482 static BIN_ATTR_RO(vad, 0/* real length varies */); 483 static BIN_ATTR_RO(vdd, 0/* real length varies */); 484 485 static struct bin_attribute *w1_ds2438_bin_attrs[] = { 486 &bin_attr_iad, 487 &bin_attr_page0, 488 &bin_attr_page1, 489 &bin_attr_offset, 490 &bin_attr_temperature, 491 &bin_attr_vad, 492 &bin_attr_vdd, 493 NULL, 494 }; 495 496 static const struct attribute_group w1_ds2438_group = { 497 .bin_attrs = w1_ds2438_bin_attrs, 498 }; 499 500 static const struct attribute_group *w1_ds2438_groups[] = { 501 &w1_ds2438_group, 502 NULL, 503 }; 504 505 static const struct w1_family_ops w1_ds2438_fops = { 506 .groups = w1_ds2438_groups, 507 }; 508 509 static struct w1_family w1_ds2438_family = { 510 .fid = W1_FAMILY_DS2438, 511 .fops = &w1_ds2438_fops, 512 }; 513 module_w1_family(w1_ds2438_family); 514 515 MODULE_LICENSE("GPL"); 516 MODULE_AUTHOR("Mariusz Bialonczyk <manio@skyboo.net>"); 517 MODULE_DESCRIPTION("1-wire driver for Maxim/Dallas DS2438 Smart Battery Monitor"); 518 MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2438)); 519