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