| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * AD7280A Lithium Ion Battery Monitoring System |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright 2011 Analog Devices Inc. |
|---|
| 5 | | - * |
|---|
| 6 | | - * Licensed under the GPL-2. |
|---|
| 7 | 6 | */ |
|---|
| 8 | 7 | |
|---|
| 8 | +#include <linux/crc8.h> |
|---|
| 9 | 9 | #include <linux/device.h> |
|---|
| 10 | 10 | #include <linux/kernel.h> |
|---|
| 11 | 11 | #include <linux/slab.h> |
|---|
| .. | .. |
|---|
| 96 | 96 | #define AD7280A_NUM_CH (AD7280A_AUX_ADC_6 - \ |
|---|
| 97 | 97 | AD7280A_CELL_VOLTAGE_1 + 1) |
|---|
| 98 | 98 | |
|---|
| 99 | +#define AD7280A_CALC_VOLTAGE_CHAN_NUM(d, c) (((d) * AD7280A_CELLS_PER_DEV) + \ |
|---|
| 100 | + (c)) |
|---|
| 101 | +#define AD7280A_CALC_TEMP_CHAN_NUM(d, c) (((d) * AD7280A_CELLS_PER_DEV) + \ |
|---|
| 102 | + (c) - AD7280A_CELLS_PER_DEV) |
|---|
| 103 | + |
|---|
| 99 | 104 | #define AD7280A_DEVADDR_MASTER 0 |
|---|
| 100 | 105 | #define AD7280A_DEVADDR_ALL 0x1F |
|---|
| 101 | 106 | /* 5-bit device address is sent LSB first */ |
|---|
| 102 | 107 | static unsigned int ad7280a_devaddr(unsigned int addr) |
|---|
| 103 | 108 | { |
|---|
| 104 | 109 | return ((addr & 0x1) << 4) | |
|---|
| 105 | | - ((addr & 0x2) << 3) | |
|---|
| 110 | + ((addr & 0x2) << 2) | |
|---|
| 106 | 111 | (addr & 0x4) | |
|---|
| 107 | | - ((addr & 0x8) >> 3) | |
|---|
| 112 | + ((addr & 0x8) >> 2) | |
|---|
| 108 | 113 | ((addr & 0x10) >> 4); |
|---|
| 109 | 114 | } |
|---|
| 110 | 115 | |
|---|
| .. | .. |
|---|
| 121 | 126 | * P(x) = x^8 + x^5 + x^3 + x^2 + x^1 + x^0 = 0b100101111 => 0x2F |
|---|
| 122 | 127 | */ |
|---|
| 123 | 128 | #define POLYNOM 0x2F |
|---|
| 124 | | -#define POLYNOM_ORDER 8 |
|---|
| 125 | | -#define HIGHBIT (1 << (POLYNOM_ORDER - 1)) |
|---|
| 126 | 129 | |
|---|
| 127 | 130 | struct ad7280_state { |
|---|
| 128 | 131 | struct spi_device *spi; |
|---|
| .. | .. |
|---|
| 131 | 134 | int slave_num; |
|---|
| 132 | 135 | int scan_cnt; |
|---|
| 133 | 136 | int readback_delay_us; |
|---|
| 134 | | - unsigned char crc_tab[256]; |
|---|
| 137 | + unsigned char crc_tab[CRC8_TABLE_SIZE]; |
|---|
| 135 | 138 | unsigned char ctrl_hb; |
|---|
| 136 | 139 | unsigned char ctrl_lb; |
|---|
| 137 | 140 | unsigned char cell_threshhigh; |
|---|
| .. | .. |
|---|
| 143 | 146 | |
|---|
| 144 | 147 | __be32 buf[2] ____cacheline_aligned; |
|---|
| 145 | 148 | }; |
|---|
| 146 | | - |
|---|
| 147 | | -static void ad7280_crc8_build_table(unsigned char *crc_tab) |
|---|
| 148 | | -{ |
|---|
| 149 | | - unsigned char bit, crc; |
|---|
| 150 | | - int cnt, i; |
|---|
| 151 | | - |
|---|
| 152 | | - for (cnt = 0; cnt < 256; cnt++) { |
|---|
| 153 | | - crc = cnt; |
|---|
| 154 | | - for (i = 0; i < 8; i++) { |
|---|
| 155 | | - bit = crc & HIGHBIT; |
|---|
| 156 | | - crc <<= 1; |
|---|
| 157 | | - if (bit) |
|---|
| 158 | | - crc ^= POLYNOM; |
|---|
| 159 | | - } |
|---|
| 160 | | - crc_tab[cnt] = crc; |
|---|
| 161 | | - } |
|---|
| 162 | | -} |
|---|
| 163 | 149 | |
|---|
| 164 | 150 | static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned int val) |
|---|
| 165 | 151 | { |
|---|
| .. | .. |
|---|
| 348 | 334 | return sum; |
|---|
| 349 | 335 | } |
|---|
| 350 | 336 | |
|---|
| 337 | +static void ad7280_sw_power_down(void *data) |
|---|
| 338 | +{ |
|---|
| 339 | + struct ad7280_state *st = data; |
|---|
| 340 | + |
|---|
| 341 | + ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1, |
|---|
| 342 | + AD7280A_CTRL_HB_PWRDN_SW | st->ctrl_hb); |
|---|
| 343 | +} |
|---|
| 344 | + |
|---|
| 351 | 345 | static int ad7280_chain_setup(struct ad7280_state *st) |
|---|
| 352 | 346 | { |
|---|
| 353 | 347 | unsigned int val, n; |
|---|
| .. | .. |
|---|
| 368 | 362 | AD7280A_CTRL_LB_MUST_SET | |
|---|
| 369 | 363 | st->ctrl_lb); |
|---|
| 370 | 364 | if (ret) |
|---|
| 371 | | - return ret; |
|---|
| 365 | + goto error_power_down; |
|---|
| 372 | 366 | |
|---|
| 373 | 367 | ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ, 1, |
|---|
| 374 | 368 | AD7280A_CONTROL_LB << 2); |
|---|
| 375 | 369 | if (ret) |
|---|
| 376 | | - return ret; |
|---|
| 370 | + goto error_power_down; |
|---|
| 377 | 371 | |
|---|
| 378 | 372 | for (n = 0; n <= AD7280A_MAX_CHAIN; n++) { |
|---|
| 379 | 373 | ret = __ad7280_read32(st, &val); |
|---|
| 380 | 374 | if (ret) |
|---|
| 381 | | - return ret; |
|---|
| 375 | + goto error_power_down; |
|---|
| 382 | 376 | |
|---|
| 383 | 377 | if (val == 0) |
|---|
| 384 | 378 | return n - 1; |
|---|
| 385 | 379 | |
|---|
| 386 | | - if (ad7280_check_crc(st, val)) |
|---|
| 387 | | - return -EIO; |
|---|
| 380 | + if (ad7280_check_crc(st, val)) { |
|---|
| 381 | + ret = -EIO; |
|---|
| 382 | + goto error_power_down; |
|---|
| 383 | + } |
|---|
| 388 | 384 | |
|---|
| 389 | | - if (n != ad7280a_devaddr(val >> 27)) |
|---|
| 390 | | - return -EIO; |
|---|
| 385 | + if (n != ad7280a_devaddr(val >> 27)) { |
|---|
| 386 | + ret = -EIO; |
|---|
| 387 | + goto error_power_down; |
|---|
| 388 | + } |
|---|
| 391 | 389 | } |
|---|
| 390 | + ret = -EFAULT; |
|---|
| 392 | 391 | |
|---|
| 393 | | - return -EFAULT; |
|---|
| 392 | +error_power_down: |
|---|
| 393 | + ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1, |
|---|
| 394 | + AD7280A_CTRL_HB_PWRDN_SW | st->ctrl_hb); |
|---|
| 395 | + |
|---|
| 396 | + return ret; |
|---|
| 394 | 397 | } |
|---|
| 395 | 398 | |
|---|
| 396 | 399 | static ssize_t ad7280_show_balance_sw(struct device *dev, |
|---|
| .. | .. |
|---|
| 497 | 500 | .attrs = ad7280_attributes, |
|---|
| 498 | 501 | }; |
|---|
| 499 | 502 | |
|---|
| 503 | +static void ad7280_voltage_channel_init(struct iio_chan_spec *chan, int i) |
|---|
| 504 | +{ |
|---|
| 505 | + chan->type = IIO_VOLTAGE; |
|---|
| 506 | + chan->differential = 1; |
|---|
| 507 | + chan->channel = i; |
|---|
| 508 | + chan->channel2 = chan->channel + 1; |
|---|
| 509 | +} |
|---|
| 510 | + |
|---|
| 511 | +static void ad7280_temp_channel_init(struct iio_chan_spec *chan, int i) |
|---|
| 512 | +{ |
|---|
| 513 | + chan->type = IIO_TEMP; |
|---|
| 514 | + chan->channel = i; |
|---|
| 515 | +} |
|---|
| 516 | + |
|---|
| 517 | +static void ad7280_common_fields_init(struct iio_chan_spec *chan, int addr, |
|---|
| 518 | + int cnt) |
|---|
| 519 | +{ |
|---|
| 520 | + chan->indexed = 1; |
|---|
| 521 | + chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); |
|---|
| 522 | + chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); |
|---|
| 523 | + chan->address = addr; |
|---|
| 524 | + chan->scan_index = cnt; |
|---|
| 525 | + chan->scan_type.sign = 'u'; |
|---|
| 526 | + chan->scan_type.realbits = 12; |
|---|
| 527 | + chan->scan_type.storagebits = 32; |
|---|
| 528 | +} |
|---|
| 529 | + |
|---|
| 530 | +static void ad7280_total_voltage_channel_init(struct iio_chan_spec *chan, |
|---|
| 531 | + int cnt, int dev) |
|---|
| 532 | +{ |
|---|
| 533 | + chan->type = IIO_VOLTAGE; |
|---|
| 534 | + chan->differential = 1; |
|---|
| 535 | + chan->channel = 0; |
|---|
| 536 | + chan->channel2 = dev * AD7280A_CELLS_PER_DEV; |
|---|
| 537 | + chan->address = AD7280A_ALL_CELLS; |
|---|
| 538 | + chan->indexed = 1; |
|---|
| 539 | + chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); |
|---|
| 540 | + chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); |
|---|
| 541 | + chan->scan_index = cnt; |
|---|
| 542 | + chan->scan_type.sign = 'u'; |
|---|
| 543 | + chan->scan_type.realbits = 32; |
|---|
| 544 | + chan->scan_type.storagebits = 32; |
|---|
| 545 | +} |
|---|
| 546 | + |
|---|
| 547 | +static void ad7280_timestamp_channel_init(struct iio_chan_spec *chan, int cnt) |
|---|
| 548 | +{ |
|---|
| 549 | + chan->type = IIO_TIMESTAMP; |
|---|
| 550 | + chan->channel = -1; |
|---|
| 551 | + chan->scan_index = cnt; |
|---|
| 552 | + chan->scan_type.sign = 's'; |
|---|
| 553 | + chan->scan_type.realbits = 64; |
|---|
| 554 | + chan->scan_type.storagebits = 64; |
|---|
| 555 | +} |
|---|
| 556 | + |
|---|
| 557 | +static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt) |
|---|
| 558 | +{ |
|---|
| 559 | + int addr, ch, i; |
|---|
| 560 | + struct iio_chan_spec *chan; |
|---|
| 561 | + |
|---|
| 562 | + for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_AUX_ADC_6; ch++) { |
|---|
| 563 | + chan = &st->channels[*cnt]; |
|---|
| 564 | + |
|---|
| 565 | + if (ch < AD7280A_AUX_ADC_1) { |
|---|
| 566 | + i = AD7280A_CALC_VOLTAGE_CHAN_NUM(dev, ch); |
|---|
| 567 | + ad7280_voltage_channel_init(chan, i); |
|---|
| 568 | + } else { |
|---|
| 569 | + i = AD7280A_CALC_TEMP_CHAN_NUM(dev, ch); |
|---|
| 570 | + ad7280_temp_channel_init(chan, i); |
|---|
| 571 | + } |
|---|
| 572 | + |
|---|
| 573 | + addr = ad7280a_devaddr(dev) << 8 | ch; |
|---|
| 574 | + ad7280_common_fields_init(chan, addr, *cnt); |
|---|
| 575 | + |
|---|
| 576 | + (*cnt)++; |
|---|
| 577 | + } |
|---|
| 578 | +} |
|---|
| 579 | + |
|---|
| 500 | 580 | static int ad7280_channel_init(struct ad7280_state *st) |
|---|
| 501 | 581 | { |
|---|
| 502 | | - int dev, ch, cnt; |
|---|
| 582 | + int dev, cnt = 0; |
|---|
| 503 | 583 | |
|---|
| 504 | | - st->channels = kcalloc((st->slave_num + 1) * 12 + 2, |
|---|
| 505 | | - sizeof(*st->channels), GFP_KERNEL); |
|---|
| 584 | + st->channels = devm_kcalloc(&st->spi->dev, (st->slave_num + 1) * 12 + 2, |
|---|
| 585 | + sizeof(*st->channels), GFP_KERNEL); |
|---|
| 506 | 586 | if (!st->channels) |
|---|
| 507 | 587 | return -ENOMEM; |
|---|
| 508 | 588 | |
|---|
| 509 | | - for (dev = 0, cnt = 0; dev <= st->slave_num; dev++) |
|---|
| 510 | | - for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_AUX_ADC_6; |
|---|
| 511 | | - ch++, cnt++) { |
|---|
| 512 | | - if (ch < AD7280A_AUX_ADC_1) { |
|---|
| 513 | | - st->channels[cnt].type = IIO_VOLTAGE; |
|---|
| 514 | | - st->channels[cnt].differential = 1; |
|---|
| 515 | | - st->channels[cnt].channel = (dev * 6) + ch; |
|---|
| 516 | | - st->channels[cnt].channel2 = |
|---|
| 517 | | - st->channels[cnt].channel + 1; |
|---|
| 518 | | - } else { |
|---|
| 519 | | - st->channels[cnt].type = IIO_TEMP; |
|---|
| 520 | | - st->channels[cnt].channel = (dev * 6) + ch - 6; |
|---|
| 521 | | - } |
|---|
| 522 | | - st->channels[cnt].indexed = 1; |
|---|
| 523 | | - st->channels[cnt].info_mask_separate = |
|---|
| 524 | | - BIT(IIO_CHAN_INFO_RAW); |
|---|
| 525 | | - st->channels[cnt].info_mask_shared_by_type = |
|---|
| 526 | | - BIT(IIO_CHAN_INFO_SCALE); |
|---|
| 527 | | - st->channels[cnt].address = |
|---|
| 528 | | - ad7280a_devaddr(dev) << 8 | ch; |
|---|
| 529 | | - st->channels[cnt].scan_index = cnt; |
|---|
| 530 | | - st->channels[cnt].scan_type.sign = 'u'; |
|---|
| 531 | | - st->channels[cnt].scan_type.realbits = 12; |
|---|
| 532 | | - st->channels[cnt].scan_type.storagebits = 32; |
|---|
| 533 | | - st->channels[cnt].scan_type.shift = 0; |
|---|
| 534 | | - } |
|---|
| 589 | + for (dev = 0; dev <= st->slave_num; dev++) |
|---|
| 590 | + ad7280_init_dev_channels(st, dev, &cnt); |
|---|
| 535 | 591 | |
|---|
| 536 | | - st->channels[cnt].type = IIO_VOLTAGE; |
|---|
| 537 | | - st->channels[cnt].differential = 1; |
|---|
| 538 | | - st->channels[cnt].channel = 0; |
|---|
| 539 | | - st->channels[cnt].channel2 = dev * 6; |
|---|
| 540 | | - st->channels[cnt].address = AD7280A_ALL_CELLS; |
|---|
| 541 | | - st->channels[cnt].indexed = 1; |
|---|
| 542 | | - st->channels[cnt].info_mask_separate = BIT(IIO_CHAN_INFO_RAW); |
|---|
| 543 | | - st->channels[cnt].info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); |
|---|
| 544 | | - st->channels[cnt].scan_index = cnt; |
|---|
| 545 | | - st->channels[cnt].scan_type.sign = 'u'; |
|---|
| 546 | | - st->channels[cnt].scan_type.realbits = 32; |
|---|
| 547 | | - st->channels[cnt].scan_type.storagebits = 32; |
|---|
| 548 | | - st->channels[cnt].scan_type.shift = 0; |
|---|
| 592 | + ad7280_total_voltage_channel_init(&st->channels[cnt], cnt, dev); |
|---|
| 549 | 593 | cnt++; |
|---|
| 550 | | - st->channels[cnt].type = IIO_TIMESTAMP; |
|---|
| 551 | | - st->channels[cnt].channel = -1; |
|---|
| 552 | | - st->channels[cnt].scan_index = cnt; |
|---|
| 553 | | - st->channels[cnt].scan_type.sign = 's'; |
|---|
| 554 | | - st->channels[cnt].scan_type.realbits = 64; |
|---|
| 555 | | - st->channels[cnt].scan_type.storagebits = 64; |
|---|
| 556 | | - st->channels[cnt].scan_type.shift = 0; |
|---|
| 594 | + ad7280_timestamp_channel_init(&st->channels[cnt], cnt); |
|---|
| 557 | 595 | |
|---|
| 558 | 596 | return cnt + 1; |
|---|
| 559 | 597 | } |
|---|
| 560 | 598 | |
|---|
| 599 | +static int ad7280_balance_switch_attr_init(struct iio_dev_attr *attr, |
|---|
| 600 | + struct device *dev, int addr, int i) |
|---|
| 601 | +{ |
|---|
| 602 | + attr->address = addr; |
|---|
| 603 | + attr->dev_attr.attr.mode = 0644; |
|---|
| 604 | + attr->dev_attr.show = ad7280_show_balance_sw; |
|---|
| 605 | + attr->dev_attr.store = ad7280_store_balance_sw; |
|---|
| 606 | + attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, |
|---|
| 607 | + "in%d-in%d_balance_switch_en", |
|---|
| 608 | + i, i + 1); |
|---|
| 609 | + if (!attr->dev_attr.attr.name) |
|---|
| 610 | + return -ENOMEM; |
|---|
| 611 | + |
|---|
| 612 | + return 0; |
|---|
| 613 | +} |
|---|
| 614 | + |
|---|
| 615 | +static int ad7280_balance_timer_attr_init(struct iio_dev_attr *attr, |
|---|
| 616 | + struct device *dev, int addr, int i) |
|---|
| 617 | +{ |
|---|
| 618 | + attr->address = addr; |
|---|
| 619 | + attr->dev_attr.attr.mode = 0644; |
|---|
| 620 | + attr->dev_attr.show = ad7280_show_balance_timer; |
|---|
| 621 | + attr->dev_attr.store = ad7280_store_balance_timer; |
|---|
| 622 | + attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, |
|---|
| 623 | + "in%d-in%d_balance_timer", |
|---|
| 624 | + i, i + 1); |
|---|
| 625 | + if (!attr->dev_attr.attr.name) |
|---|
| 626 | + return -ENOMEM; |
|---|
| 627 | + |
|---|
| 628 | + return 0; |
|---|
| 629 | +} |
|---|
| 630 | + |
|---|
| 631 | +static int ad7280_init_dev_attrs(struct ad7280_state *st, int dev, int *cnt) |
|---|
| 632 | +{ |
|---|
| 633 | + int addr, ch, i, ret; |
|---|
| 634 | + struct iio_dev_attr *iio_attr; |
|---|
| 635 | + struct device *sdev = &st->spi->dev; |
|---|
| 636 | + |
|---|
| 637 | + for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6; ch++) { |
|---|
| 638 | + iio_attr = &st->iio_attr[*cnt]; |
|---|
| 639 | + addr = ad7280a_devaddr(dev) << 8 | ch; |
|---|
| 640 | + i = dev * AD7280A_CELLS_PER_DEV + ch; |
|---|
| 641 | + |
|---|
| 642 | + ret = ad7280_balance_switch_attr_init(iio_attr, sdev, addr, i); |
|---|
| 643 | + if (ret < 0) |
|---|
| 644 | + return ret; |
|---|
| 645 | + |
|---|
| 646 | + ad7280_attributes[*cnt] = &iio_attr->dev_attr.attr; |
|---|
| 647 | + |
|---|
| 648 | + (*cnt)++; |
|---|
| 649 | + iio_attr = &st->iio_attr[*cnt]; |
|---|
| 650 | + addr = ad7280a_devaddr(dev) << 8 | (AD7280A_CB1_TIMER + ch); |
|---|
| 651 | + |
|---|
| 652 | + ret = ad7280_balance_timer_attr_init(iio_attr, sdev, addr, i); |
|---|
| 653 | + if (ret < 0) |
|---|
| 654 | + return ret; |
|---|
| 655 | + |
|---|
| 656 | + ad7280_attributes[*cnt] = &iio_attr->dev_attr.attr; |
|---|
| 657 | + (*cnt)++; |
|---|
| 658 | + } |
|---|
| 659 | + |
|---|
| 660 | + ad7280_attributes[*cnt] = NULL; |
|---|
| 661 | + |
|---|
| 662 | + return 0; |
|---|
| 663 | +} |
|---|
| 664 | + |
|---|
| 561 | 665 | static int ad7280_attr_init(struct ad7280_state *st) |
|---|
| 562 | 666 | { |
|---|
| 563 | | - int dev, ch, cnt; |
|---|
| 667 | + int dev, cnt = 0, ret; |
|---|
| 564 | 668 | |
|---|
| 565 | | - st->iio_attr = kcalloc(2, sizeof(*st->iio_attr) * |
|---|
| 566 | | - (st->slave_num + 1) * AD7280A_CELLS_PER_DEV, |
|---|
| 567 | | - GFP_KERNEL); |
|---|
| 669 | + st->iio_attr = devm_kcalloc(&st->spi->dev, 2, sizeof(*st->iio_attr) * |
|---|
| 670 | + (st->slave_num + 1) * AD7280A_CELLS_PER_DEV, |
|---|
| 671 | + GFP_KERNEL); |
|---|
| 568 | 672 | if (!st->iio_attr) |
|---|
| 569 | 673 | return -ENOMEM; |
|---|
| 570 | 674 | |
|---|
| 571 | | - for (dev = 0, cnt = 0; dev <= st->slave_num; dev++) |
|---|
| 572 | | - for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6; |
|---|
| 573 | | - ch++, cnt++) { |
|---|
| 574 | | - st->iio_attr[cnt].address = |
|---|
| 575 | | - ad7280a_devaddr(dev) << 8 | ch; |
|---|
| 576 | | - st->iio_attr[cnt].dev_attr.attr.mode = |
|---|
| 577 | | - 0644; |
|---|
| 578 | | - st->iio_attr[cnt].dev_attr.show = |
|---|
| 579 | | - ad7280_show_balance_sw; |
|---|
| 580 | | - st->iio_attr[cnt].dev_attr.store = |
|---|
| 581 | | - ad7280_store_balance_sw; |
|---|
| 582 | | - st->iio_attr[cnt].dev_attr.attr.name = |
|---|
| 583 | | - kasprintf(GFP_KERNEL, |
|---|
| 584 | | - "in%d-in%d_balance_switch_en", |
|---|
| 585 | | - dev * AD7280A_CELLS_PER_DEV + ch, |
|---|
| 586 | | - dev * AD7280A_CELLS_PER_DEV + ch + 1); |
|---|
| 587 | | - ad7280_attributes[cnt] = |
|---|
| 588 | | - &st->iio_attr[cnt].dev_attr.attr; |
|---|
| 589 | | - cnt++; |
|---|
| 590 | | - st->iio_attr[cnt].address = |
|---|
| 591 | | - ad7280a_devaddr(dev) << 8 | |
|---|
| 592 | | - (AD7280A_CB1_TIMER + ch); |
|---|
| 593 | | - st->iio_attr[cnt].dev_attr.attr.mode = |
|---|
| 594 | | - 0644; |
|---|
| 595 | | - st->iio_attr[cnt].dev_attr.show = |
|---|
| 596 | | - ad7280_show_balance_timer; |
|---|
| 597 | | - st->iio_attr[cnt].dev_attr.store = |
|---|
| 598 | | - ad7280_store_balance_timer; |
|---|
| 599 | | - st->iio_attr[cnt].dev_attr.attr.name = |
|---|
| 600 | | - kasprintf(GFP_KERNEL, |
|---|
| 601 | | - "in%d-in%d_balance_timer", |
|---|
| 602 | | - dev * AD7280A_CELLS_PER_DEV + ch, |
|---|
| 603 | | - dev * AD7280A_CELLS_PER_DEV + ch + 1); |
|---|
| 604 | | - ad7280_attributes[cnt] = |
|---|
| 605 | | - &st->iio_attr[cnt].dev_attr.attr; |
|---|
| 606 | | - } |
|---|
| 607 | | - |
|---|
| 608 | | - ad7280_attributes[cnt] = NULL; |
|---|
| 675 | + for (dev = 0; dev <= st->slave_num; dev++) { |
|---|
| 676 | + ret = ad7280_init_dev_attrs(st, dev, &cnt); |
|---|
| 677 | + if (ret < 0) |
|---|
| 678 | + return ret; |
|---|
| 679 | + } |
|---|
| 609 | 680 | |
|---|
| 610 | 681 | return 0; |
|---|
| 611 | 682 | } |
|---|
| .. | .. |
|---|
| 619 | 690 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); |
|---|
| 620 | 691 | unsigned int val; |
|---|
| 621 | 692 | |
|---|
| 622 | | - switch ((u32)this_attr->address) { |
|---|
| 693 | + switch (this_attr->address) { |
|---|
| 623 | 694 | case AD7280A_CELL_OVERVOLTAGE: |
|---|
| 624 | 695 | val = 1000 + (st->cell_threshhigh * 1568) / 100; |
|---|
| 625 | 696 | break; |
|---|
| .. | .. |
|---|
| 655 | 726 | if (ret) |
|---|
| 656 | 727 | return ret; |
|---|
| 657 | 728 | |
|---|
| 658 | | - switch ((u32)this_attr->address) { |
|---|
| 729 | + switch (this_attr->address) { |
|---|
| 659 | 730 | case AD7280A_CELL_OVERVOLTAGE: |
|---|
| 660 | 731 | case AD7280A_CELL_UNDERVOLTAGE: |
|---|
| 661 | 732 | val = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */ |
|---|
| .. | .. |
|---|
| 671 | 742 | val = clamp(val, 0L, 0xFFL); |
|---|
| 672 | 743 | |
|---|
| 673 | 744 | mutex_lock(&st->lock); |
|---|
| 674 | | - switch ((u32)this_attr->address) { |
|---|
| 745 | + switch (this_attr->address) { |
|---|
| 675 | 746 | case AD7280A_CELL_OVERVOLTAGE: |
|---|
| 676 | 747 | st->cell_threshhigh = val; |
|---|
| 677 | 748 | break; |
|---|
| .. | .. |
|---|
| 712 | 783 | for (i = 0; i < st->scan_cnt; i++) { |
|---|
| 713 | 784 | if (((channels[i] >> 23) & 0xF) <= AD7280A_CELL_VOLTAGE_6) { |
|---|
| 714 | 785 | if (((channels[i] >> 11) & 0xFFF) >= |
|---|
| 715 | | - st->cell_threshhigh) |
|---|
| 716 | | - iio_push_event(indio_dev, |
|---|
| 717 | | - IIO_EVENT_CODE(IIO_VOLTAGE, |
|---|
| 718 | | - 1, |
|---|
| 719 | | - 0, |
|---|
| 720 | | - IIO_EV_DIR_RISING, |
|---|
| 721 | | - IIO_EV_TYPE_THRESH, |
|---|
| 722 | | - 0, 0, 0), |
|---|
| 786 | + st->cell_threshhigh) { |
|---|
| 787 | + u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, |
|---|
| 788 | + IIO_EV_DIR_RISING, |
|---|
| 789 | + IIO_EV_TYPE_THRESH, |
|---|
| 790 | + 0, 0, 0); |
|---|
| 791 | + iio_push_event(indio_dev, tmp, |
|---|
| 723 | 792 | iio_get_time_ns(indio_dev)); |
|---|
| 724 | | - else if (((channels[i] >> 11) & 0xFFF) <= |
|---|
| 725 | | - st->cell_threshlow) |
|---|
| 726 | | - iio_push_event(indio_dev, |
|---|
| 727 | | - IIO_EVENT_CODE(IIO_VOLTAGE, |
|---|
| 728 | | - 1, |
|---|
| 729 | | - 0, |
|---|
| 730 | | - IIO_EV_DIR_FALLING, |
|---|
| 731 | | - IIO_EV_TYPE_THRESH, |
|---|
| 732 | | - 0, 0, 0), |
|---|
| 793 | + } else if (((channels[i] >> 11) & 0xFFF) <= |
|---|
| 794 | + st->cell_threshlow) { |
|---|
| 795 | + u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, |
|---|
| 796 | + IIO_EV_DIR_FALLING, |
|---|
| 797 | + IIO_EV_TYPE_THRESH, |
|---|
| 798 | + 0, 0, 0); |
|---|
| 799 | + iio_push_event(indio_dev, tmp, |
|---|
| 733 | 800 | iio_get_time_ns(indio_dev)); |
|---|
| 801 | + } |
|---|
| 734 | 802 | } else { |
|---|
| 735 | | - if (((channels[i] >> 11) & 0xFFF) >= st->aux_threshhigh) |
|---|
| 736 | | - iio_push_event(indio_dev, |
|---|
| 737 | | - IIO_UNMOD_EVENT_CODE( |
|---|
| 738 | | - IIO_TEMP, |
|---|
| 739 | | - 0, |
|---|
| 803 | + if (((channels[i] >> 11) & 0xFFF) >= |
|---|
| 804 | + st->aux_threshhigh) { |
|---|
| 805 | + u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, |
|---|
| 740 | 806 | IIO_EV_TYPE_THRESH, |
|---|
| 741 | | - IIO_EV_DIR_RISING), |
|---|
| 807 | + IIO_EV_DIR_RISING); |
|---|
| 808 | + iio_push_event(indio_dev, tmp, |
|---|
| 742 | 809 | iio_get_time_ns(indio_dev)); |
|---|
| 743 | | - else if (((channels[i] >> 11) & 0xFFF) <= |
|---|
| 744 | | - st->aux_threshlow) |
|---|
| 745 | | - iio_push_event(indio_dev, |
|---|
| 746 | | - IIO_UNMOD_EVENT_CODE( |
|---|
| 747 | | - IIO_TEMP, |
|---|
| 748 | | - 0, |
|---|
| 810 | + } else if (((channels[i] >> 11) & 0xFFF) <= |
|---|
| 811 | + st->aux_threshlow) { |
|---|
| 812 | + u64 tmp = IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, |
|---|
| 749 | 813 | IIO_EV_TYPE_THRESH, |
|---|
| 750 | | - IIO_EV_DIR_FALLING), |
|---|
| 814 | + IIO_EV_DIR_FALLING); |
|---|
| 815 | + iio_push_event(indio_dev, tmp, |
|---|
| 751 | 816 | iio_get_time_ns(indio_dev)); |
|---|
| 817 | + } |
|---|
| 752 | 818 | } |
|---|
| 753 | 819 | } |
|---|
| 754 | 820 | |
|---|
| .. | .. |
|---|
| 758 | 824 | return IRQ_HANDLED; |
|---|
| 759 | 825 | } |
|---|
| 760 | 826 | |
|---|
| 827 | +/* Note: No need to fix checkpatch warning that reads: |
|---|
| 828 | + * CHECK: spaces preferred around that '-' (ctx:VxV) |
|---|
| 829 | + * The function argument is stringified and doesn't need a fix |
|---|
| 830 | + */ |
|---|
| 761 | 831 | static IIO_DEVICE_ATTR_NAMED(in_thresh_low_value, |
|---|
| 762 | | - in_voltage-voltage_thresh_low_value, |
|---|
| 763 | | - 0644, |
|---|
| 764 | | - ad7280_read_channel_config, |
|---|
| 765 | | - ad7280_write_channel_config, |
|---|
| 766 | | - AD7280A_CELL_UNDERVOLTAGE); |
|---|
| 832 | + in_voltage-voltage_thresh_low_value, |
|---|
| 833 | + 0644, |
|---|
| 834 | + ad7280_read_channel_config, |
|---|
| 835 | + ad7280_write_channel_config, |
|---|
| 836 | + AD7280A_CELL_UNDERVOLTAGE); |
|---|
| 767 | 837 | |
|---|
| 768 | 838 | static IIO_DEVICE_ATTR_NAMED(in_thresh_high_value, |
|---|
| 769 | | - in_voltage-voltage_thresh_high_value, |
|---|
| 770 | | - 0644, |
|---|
| 771 | | - ad7280_read_channel_config, |
|---|
| 772 | | - ad7280_write_channel_config, |
|---|
| 773 | | - AD7280A_CELL_OVERVOLTAGE); |
|---|
| 839 | + in_voltage-voltage_thresh_high_value, |
|---|
| 840 | + 0644, |
|---|
| 841 | + ad7280_read_channel_config, |
|---|
| 842 | + ad7280_write_channel_config, |
|---|
| 843 | + AD7280A_CELL_OVERVOLTAGE); |
|---|
| 774 | 844 | |
|---|
| 775 | 845 | static IIO_DEVICE_ATTR(in_temp_thresh_low_value, |
|---|
| 776 | | - 0644, |
|---|
| 777 | | - ad7280_read_channel_config, |
|---|
| 778 | | - ad7280_write_channel_config, |
|---|
| 779 | | - AD7280A_AUX_ADC_UNDERVOLTAGE); |
|---|
| 846 | + 0644, |
|---|
| 847 | + ad7280_read_channel_config, |
|---|
| 848 | + ad7280_write_channel_config, |
|---|
| 849 | + AD7280A_AUX_ADC_UNDERVOLTAGE); |
|---|
| 780 | 850 | |
|---|
| 781 | 851 | static IIO_DEVICE_ATTR(in_temp_thresh_high_value, |
|---|
| 782 | | - 0644, |
|---|
| 783 | | - ad7280_read_channel_config, |
|---|
| 784 | | - ad7280_write_channel_config, |
|---|
| 785 | | - AD7280A_AUX_ADC_OVERVOLTAGE); |
|---|
| 852 | + 0644, |
|---|
| 853 | + ad7280_read_channel_config, |
|---|
| 854 | + ad7280_write_channel_config, |
|---|
| 855 | + AD7280A_AUX_ADC_OVERVOLTAGE); |
|---|
| 786 | 856 | |
|---|
| 787 | 857 | static struct attribute *ad7280_event_attributes[] = { |
|---|
| 788 | 858 | &iio_dev_attr_in_thresh_low_value.dev_attr.attr, |
|---|
| .. | .. |
|---|
| 850 | 920 | const struct ad7280_platform_data *pdata = dev_get_platdata(&spi->dev); |
|---|
| 851 | 921 | struct ad7280_state *st; |
|---|
| 852 | 922 | int ret; |
|---|
| 853 | | - const unsigned short tACQ_ns[4] = {465, 1010, 1460, 1890}; |
|---|
| 854 | | - const unsigned short nAVG[4] = {1, 2, 4, 8}; |
|---|
| 923 | + const unsigned short t_acq_ns[4] = {465, 1010, 1460, 1890}; |
|---|
| 924 | + const unsigned short n_avg[4] = {1, 2, 4, 8}; |
|---|
| 855 | 925 | struct iio_dev *indio_dev; |
|---|
| 856 | 926 | |
|---|
| 857 | 927 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); |
|---|
| .. | .. |
|---|
| 866 | 936 | if (!pdata) |
|---|
| 867 | 937 | pdata = &ad7793_default_pdata; |
|---|
| 868 | 938 | |
|---|
| 869 | | - ad7280_crc8_build_table(st->crc_tab); |
|---|
| 939 | + crc8_populate_msb(st->crc_tab, POLYNOM); |
|---|
| 870 | 940 | |
|---|
| 871 | 941 | st->spi->max_speed_hz = AD7280A_MAX_SPI_CLK_HZ; |
|---|
| 872 | 942 | st->spi->mode = SPI_MODE_1; |
|---|
| .. | .. |
|---|
| 886 | 956 | st->cell_threshhigh = 0xFF; |
|---|
| 887 | 957 | st->aux_threshhigh = 0xFF; |
|---|
| 888 | 958 | |
|---|
| 959 | + ret = devm_add_action_or_reset(&spi->dev, ad7280_sw_power_down, st); |
|---|
| 960 | + if (ret) |
|---|
| 961 | + return ret; |
|---|
| 962 | + |
|---|
| 889 | 963 | /* |
|---|
| 890 | 964 | * Total Conversion Time = ((tACQ + tCONV) * |
|---|
| 891 | 965 | * (Number of Conversions per Part)) − |
|---|
| .. | .. |
|---|
| 895 | 969 | */ |
|---|
| 896 | 970 | |
|---|
| 897 | 971 | st->readback_delay_us = |
|---|
| 898 | | - ((tACQ_ns[pdata->acquisition_time & 0x3] + 695) * |
|---|
| 899 | | - (AD7280A_NUM_CH * nAVG[pdata->conversion_averaging & 0x3])) |
|---|
| 900 | | - - tACQ_ns[pdata->acquisition_time & 0x3] + |
|---|
| 901 | | - st->slave_num * 250; |
|---|
| 972 | + ((t_acq_ns[pdata->acquisition_time & 0x3] + 695) * |
|---|
| 973 | + (AD7280A_NUM_CH * n_avg[pdata->conversion_averaging & 0x3])) - |
|---|
| 974 | + t_acq_ns[pdata->acquisition_time & 0x3] + st->slave_num * 250; |
|---|
| 902 | 975 | |
|---|
| 903 | 976 | /* Convert to usecs */ |
|---|
| 904 | 977 | st->readback_delay_us = DIV_ROUND_UP(st->readback_delay_us, 1000); |
|---|
| 905 | 978 | st->readback_delay_us += 5; /* Add tWAIT */ |
|---|
| 906 | 979 | |
|---|
| 907 | 980 | indio_dev->name = spi_get_device_id(spi)->name; |
|---|
| 908 | | - indio_dev->dev.parent = &spi->dev; |
|---|
| 909 | 981 | indio_dev->modes = INDIO_DIRECT_MODE; |
|---|
| 910 | 982 | |
|---|
| 911 | 983 | ret = ad7280_channel_init(st); |
|---|
| .. | .. |
|---|
| 918 | 990 | |
|---|
| 919 | 991 | ret = ad7280_attr_init(st); |
|---|
| 920 | 992 | if (ret < 0) |
|---|
| 921 | | - goto error_free_channels; |
|---|
| 993 | + return ret; |
|---|
| 922 | 994 | |
|---|
| 923 | | - ret = iio_device_register(indio_dev); |
|---|
| 995 | + ret = devm_iio_device_register(&spi->dev, indio_dev); |
|---|
| 924 | 996 | if (ret) |
|---|
| 925 | | - goto error_free_attr; |
|---|
| 997 | + return ret; |
|---|
| 926 | 998 | |
|---|
| 927 | 999 | if (spi->irq > 0) { |
|---|
| 928 | 1000 | ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, |
|---|
| 929 | 1001 | AD7280A_ALERT, 1, |
|---|
| 930 | 1002 | AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN); |
|---|
| 931 | 1003 | if (ret) |
|---|
| 932 | | - goto error_unregister; |
|---|
| 1004 | + return ret; |
|---|
| 933 | 1005 | |
|---|
| 934 | 1006 | ret = ad7280_write(st, ad7280a_devaddr(st->slave_num), |
|---|
| 935 | 1007 | AD7280A_ALERT, 0, |
|---|
| 936 | 1008 | AD7280A_ALERT_GEN_STATIC_HIGH | |
|---|
| 937 | 1009 | (pdata->chain_last_alert_ignore & 0xF)); |
|---|
| 938 | 1010 | if (ret) |
|---|
| 939 | | - goto error_unregister; |
|---|
| 1011 | + return ret; |
|---|
| 940 | 1012 | |
|---|
| 941 | | - ret = request_threaded_irq(spi->irq, |
|---|
| 942 | | - NULL, |
|---|
| 943 | | - ad7280_event_handler, |
|---|
| 944 | | - IRQF_TRIGGER_FALLING | |
|---|
| 945 | | - IRQF_ONESHOT, |
|---|
| 946 | | - indio_dev->name, |
|---|
| 947 | | - indio_dev); |
|---|
| 1013 | + ret = devm_request_threaded_irq(&spi->dev, spi->irq, |
|---|
| 1014 | + NULL, |
|---|
| 1015 | + ad7280_event_handler, |
|---|
| 1016 | + IRQF_TRIGGER_FALLING | |
|---|
| 1017 | + IRQF_ONESHOT, |
|---|
| 1018 | + indio_dev->name, |
|---|
| 1019 | + indio_dev); |
|---|
| 948 | 1020 | if (ret) |
|---|
| 949 | | - goto error_unregister; |
|---|
| 1021 | + return ret; |
|---|
| 950 | 1022 | } |
|---|
| 951 | | - |
|---|
| 952 | | - return 0; |
|---|
| 953 | | -error_unregister: |
|---|
| 954 | | - iio_device_unregister(indio_dev); |
|---|
| 955 | | - |
|---|
| 956 | | -error_free_attr: |
|---|
| 957 | | - kfree(st->iio_attr); |
|---|
| 958 | | - |
|---|
| 959 | | -error_free_channels: |
|---|
| 960 | | - kfree(st->channels); |
|---|
| 961 | | - |
|---|
| 962 | | - return ret; |
|---|
| 963 | | -} |
|---|
| 964 | | - |
|---|
| 965 | | -static int ad7280_remove(struct spi_device *spi) |
|---|
| 966 | | -{ |
|---|
| 967 | | - struct iio_dev *indio_dev = spi_get_drvdata(spi); |
|---|
| 968 | | - struct ad7280_state *st = iio_priv(indio_dev); |
|---|
| 969 | | - |
|---|
| 970 | | - if (spi->irq > 0) |
|---|
| 971 | | - free_irq(spi->irq, indio_dev); |
|---|
| 972 | | - iio_device_unregister(indio_dev); |
|---|
| 973 | | - |
|---|
| 974 | | - ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1, |
|---|
| 975 | | - AD7280A_CTRL_HB_PWRDN_SW | st->ctrl_hb); |
|---|
| 976 | | - |
|---|
| 977 | | - kfree(st->channels); |
|---|
| 978 | | - kfree(st->iio_attr); |
|---|
| 979 | 1023 | |
|---|
| 980 | 1024 | return 0; |
|---|
| 981 | 1025 | } |
|---|
| .. | .. |
|---|
| 991 | 1035 | .name = "ad7280", |
|---|
| 992 | 1036 | }, |
|---|
| 993 | 1037 | .probe = ad7280_probe, |
|---|
| 994 | | - .remove = ad7280_remove, |
|---|
| 995 | 1038 | .id_table = ad7280_id, |
|---|
| 996 | 1039 | }; |
|---|
| 997 | 1040 | module_spi_driver(ad7280_driver); |
|---|
| 998 | 1041 | |
|---|
| 999 | | -MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); |
|---|
| 1042 | +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); |
|---|
| 1000 | 1043 | MODULE_DESCRIPTION("Analog Devices AD7280A"); |
|---|
| 1001 | 1044 | MODULE_LICENSE("GPL v2"); |
|---|