diff options
author | Jerome Oufella <jerome.oufella@savoirfairelinux.com> | 2011-04-12 15:34:39 -0400 |
---|---|---|
committer | Guenter Roeck <guenter.roeck@ericsson.com> | 2011-05-19 11:19:36 -0400 |
commit | 82c7465b4dd013d19858bfeac084849ae17682c0 (patch) | |
tree | af6828f4e6cac12153100b30fbe126fe0989e1a8 /drivers/hwmon | |
parent | cc15c7ebb424e45ba2c5ceecbe52d025219ee970 (diff) |
hwmon: (sht15) add support for CRC validation
The sht15 sensor allows validating exchanges to and from the device
using a crc8 function. An utility function to reverse a byte has also
been added.
Signed-off-by: Jerome Oufella <jerome.oufella@savoirfairelinux.com>
Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/sht15.c | 192 |
1 files changed, 173 insertions, 19 deletions
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 49da089b5de9..cf4330b352ef 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * sht15.c - support for the SHT15 Temperature and Humidity Sensor | 2 | * sht15.c - support for the SHT15 Temperature and Humidity Sensor |
3 | * | 3 | * |
4 | * Portions Copyright (c) 2010-2011 Savoir-faire Linux Inc. | 4 | * Portions Copyright (c) 2010-2011 Savoir-faire Linux Inc. |
5 | * Jerome Oufella <jerome.oufella@savoirfairelinux.com> | ||
5 | * Vivien Didelot <vivien.didelot@savoirfairelinux.com> | 6 | * Vivien Didelot <vivien.didelot@savoirfairelinux.com> |
6 | * | 7 | * |
7 | * Copyright (c) 2009 Jonathan Cameron | 8 | * Copyright (c) 2009 Jonathan Cameron |
@@ -78,6 +79,42 @@ static const struct sht15_temppair temppoints[] = { | |||
78 | { 5000000, -40100 }, | 79 | { 5000000, -40100 }, |
79 | }; | 80 | }; |
80 | 81 | ||
82 | /* Table from CRC datasheet, section 2.4 */ | ||
83 | static const u8 sht15_crc8_table[] = { | ||
84 | 0, 49, 98, 83, 196, 245, 166, 151, | ||
85 | 185, 136, 219, 234, 125, 76, 31, 46, | ||
86 | 67, 114, 33, 16, 135, 182, 229, 212, | ||
87 | 250, 203, 152, 169, 62, 15, 92, 109, | ||
88 | 134, 183, 228, 213, 66, 115, 32, 17, | ||
89 | 63, 14, 93, 108, 251, 202, 153, 168, | ||
90 | 197, 244, 167, 150, 1, 48, 99, 82, | ||
91 | 124, 77, 30, 47, 184, 137, 218, 235, | ||
92 | 61, 12, 95, 110, 249, 200, 155, 170, | ||
93 | 132, 181, 230, 215, 64, 113, 34, 19, | ||
94 | 126, 79, 28, 45, 186, 139, 216, 233, | ||
95 | 199, 246, 165, 148, 3, 50, 97, 80, | ||
96 | 187, 138, 217, 232, 127, 78, 29, 44, | ||
97 | 2, 51, 96, 81, 198, 247, 164, 149, | ||
98 | 248, 201, 154, 171, 60, 13, 94, 111, | ||
99 | 65, 112, 35, 18, 133, 180, 231, 214, | ||
100 | 122, 75, 24, 41, 190, 143, 220, 237, | ||
101 | 195, 242, 161, 144, 7, 54, 101, 84, | ||
102 | 57, 8, 91, 106, 253, 204, 159, 174, | ||
103 | 128, 177, 226, 211, 68, 117, 38, 23, | ||
104 | 252, 205, 158, 175, 56, 9, 90, 107, | ||
105 | 69, 116, 39, 22, 129, 176, 227, 210, | ||
106 | 191, 142, 221, 236, 123, 74, 25, 40, | ||
107 | 6, 55, 100, 85, 194, 243, 160, 145, | ||
108 | 71, 118, 37, 20, 131, 178, 225, 208, | ||
109 | 254, 207, 156, 173, 58, 11, 88, 105, | ||
110 | 4, 53, 102, 87, 192, 241, 162, 147, | ||
111 | 189, 140, 223, 238, 121, 72, 27, 42, | ||
112 | 193, 240, 163, 146, 5, 52, 103, 86, | ||
113 | 120, 73, 26, 43, 188, 141, 222, 239, | ||
114 | 130, 179, 224, 209, 70, 119, 36, 21, | ||
115 | 59, 10, 89, 104, 255, 206, 157, 172 | ||
116 | }; | ||
117 | |||
81 | /** | 118 | /** |
82 | * struct sht15_data - device instance specific data | 119 | * struct sht15_data - device instance specific data |
83 | * @pdata: platform data (gpio's etc). | 120 | * @pdata: platform data (gpio's etc). |
@@ -86,6 +123,8 @@ static const struct sht15_temppair temppoints[] = { | |||
86 | * @val_temp: last temperature value read from device. | 123 | * @val_temp: last temperature value read from device. |
87 | * @val_humid: last humidity value read from device. | 124 | * @val_humid: last humidity value read from device. |
88 | * @val_status: last status register value read from device. | 125 | * @val_status: last status register value read from device. |
126 | * @checksum_ok: last value read from the device passed CRC validation. | ||
127 | * @checksumming: flag used to enable the data validation with CRC. | ||
89 | * @state: state identifying the action the driver is doing. | 128 | * @state: state identifying the action the driver is doing. |
90 | * @measurements_valid: are the current stored measures valid (start condition). | 129 | * @measurements_valid: are the current stored measures valid (start condition). |
91 | * @status_valid: is the current stored status valid (start condition). | 130 | * @status_valid: is the current stored status valid (start condition). |
@@ -112,6 +151,8 @@ struct sht15_data { | |||
112 | uint16_t val_temp; | 151 | uint16_t val_temp; |
113 | uint16_t val_humid; | 152 | uint16_t val_humid; |
114 | u8 val_status; | 153 | u8 val_status; |
154 | bool checksum_ok; | ||
155 | bool checksumming; | ||
115 | enum sht15_state state; | 156 | enum sht15_state state; |
116 | bool measurements_valid; | 157 | bool measurements_valid; |
117 | bool status_valid; | 158 | bool status_valid; |
@@ -129,6 +170,40 @@ struct sht15_data { | |||
129 | }; | 170 | }; |
130 | 171 | ||
131 | /** | 172 | /** |
173 | * sht15_reverse() - reverse a byte | ||
174 | * @byte: byte to reverse. | ||
175 | */ | ||
176 | static u8 sht15_reverse(u8 byte) | ||
177 | { | ||
178 | u8 i, c; | ||
179 | |||
180 | for (c = 0, i = 0; i < 8; i++) | ||
181 | c |= (!!(byte & (1 << i))) << (7 - i); | ||
182 | return c; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * sht15_crc8() - compute crc8 | ||
187 | * @data: sht15 specific data. | ||
188 | * @value: sht15 retrieved data. | ||
189 | * | ||
190 | * This implements section 2 of the CRC datasheet. | ||
191 | */ | ||
192 | static u8 sht15_crc8(struct sht15_data *data, | ||
193 | const u8 *value, | ||
194 | int len) | ||
195 | { | ||
196 | u8 crc = sht15_reverse(data->val_status & 0x0F); | ||
197 | |||
198 | while (len--) { | ||
199 | crc = sht15_crc8_table[*value ^ crc]; | ||
200 | value++; | ||
201 | } | ||
202 | |||
203 | return crc; | ||
204 | } | ||
205 | |||
206 | /** | ||
132 | * sht15_connection_reset() - reset the comms interface | 207 | * sht15_connection_reset() - reset the comms interface |
133 | * @data: sht15 specific data | 208 | * @data: sht15 specific data |
134 | * | 209 | * |
@@ -268,6 +343,26 @@ static int sht15_soft_reset(struct sht15_data *data) | |||
268 | } | 343 | } |
269 | 344 | ||
270 | /** | 345 | /** |
346 | * sht15_ack() - send a ack | ||
347 | * @data: sht15 specific data. | ||
348 | * | ||
349 | * Each byte of data is acknowledged by pulling the data line | ||
350 | * low for one clock pulse. | ||
351 | */ | ||
352 | static void sht15_ack(struct sht15_data *data) | ||
353 | { | ||
354 | gpio_direction_output(data->pdata->gpio_data, 0); | ||
355 | ndelay(SHT15_TSU); | ||
356 | gpio_set_value(data->pdata->gpio_sck, 1); | ||
357 | ndelay(SHT15_TSU); | ||
358 | gpio_set_value(data->pdata->gpio_sck, 0); | ||
359 | ndelay(SHT15_TSU); | ||
360 | gpio_set_value(data->pdata->gpio_data, 1); | ||
361 | |||
362 | gpio_direction_input(data->pdata->gpio_data); | ||
363 | } | ||
364 | |||
365 | /** | ||
271 | * sht15_end_transmission() - notify device of end of transmission | 366 | * sht15_end_transmission() - notify device of end of transmission |
272 | * @data: device state. | 367 | * @data: device state. |
273 | * | 368 | * |
@@ -338,6 +433,9 @@ static int sht15_update_status(struct sht15_data *data) | |||
338 | { | 433 | { |
339 | int ret = 0; | 434 | int ret = 0; |
340 | u8 status; | 435 | u8 status; |
436 | u8 previous_config; | ||
437 | u8 dev_checksum = 0; | ||
438 | u8 checksum_vals[2]; | ||
341 | int timeout = HZ; | 439 | int timeout = HZ; |
342 | 440 | ||
343 | mutex_lock(&data->read_lock); | 441 | mutex_lock(&data->read_lock); |
@@ -348,8 +446,40 @@ static int sht15_update_status(struct sht15_data *data) | |||
348 | goto error_ret; | 446 | goto error_ret; |
349 | status = sht15_read_byte(data); | 447 | status = sht15_read_byte(data); |
350 | 448 | ||
449 | if (data->checksumming) { | ||
450 | sht15_ack(data); | ||
451 | dev_checksum = sht15_reverse(sht15_read_byte(data)); | ||
452 | checksum_vals[0] = SHT15_READ_STATUS; | ||
453 | checksum_vals[1] = status; | ||
454 | data->checksum_ok = (sht15_crc8(data, checksum_vals, 2) | ||
455 | == dev_checksum); | ||
456 | } | ||
457 | |||
351 | sht15_end_transmission(data); | 458 | sht15_end_transmission(data); |
352 | 459 | ||
460 | /* | ||
461 | * Perform checksum validation on the received data. | ||
462 | * Specification mentions that in case a checksum verification | ||
463 | * fails, a soft reset command must be sent to the device. | ||
464 | */ | ||
465 | if (data->checksumming && !data->checksum_ok) { | ||
466 | previous_config = data->val_status & 0x07; | ||
467 | ret = sht15_soft_reset(data); | ||
468 | if (ret) | ||
469 | goto error_ret; | ||
470 | if (previous_config) { | ||
471 | ret = sht15_send_status(data, previous_config); | ||
472 | if (ret) { | ||
473 | dev_err(data->dev, | ||
474 | "CRC validation failed, unable " | ||
475 | "to restore device settings\n"); | ||
476 | goto error_ret; | ||
477 | } | ||
478 | } | ||
479 | ret = -EAGAIN; | ||
480 | goto error_ret; | ||
481 | } | ||
482 | |||
353 | data->val_status = status; | 483 | data->val_status = status; |
354 | data->status_valid = true; | 484 | data->status_valid = true; |
355 | data->last_status = jiffies; | 485 | data->last_status = jiffies; |
@@ -372,6 +502,7 @@ static int sht15_measurement(struct sht15_data *data, | |||
372 | int timeout_msecs) | 502 | int timeout_msecs) |
373 | { | 503 | { |
374 | int ret; | 504 | int ret; |
505 | u8 previous_config; | ||
375 | 506 | ||
376 | ret = sht15_send_cmd(data, command); | 507 | ret = sht15_send_cmd(data, command); |
377 | if (ret) | 508 | if (ret) |
@@ -395,6 +526,29 @@ static int sht15_measurement(struct sht15_data *data, | |||
395 | sht15_connection_reset(data); | 526 | sht15_connection_reset(data); |
396 | return -ETIME; | 527 | return -ETIME; |
397 | } | 528 | } |
529 | |||
530 | /* | ||
531 | * Perform checksum validation on the received data. | ||
532 | * Specification mentions that in case a checksum verification fails, | ||
533 | * a soft reset command must be sent to the device. | ||
534 | */ | ||
535 | if (data->checksumming && !data->checksum_ok) { | ||
536 | previous_config = data->val_status & 0x07; | ||
537 | ret = sht15_soft_reset(data); | ||
538 | if (ret) | ||
539 | return ret; | ||
540 | if (previous_config) { | ||
541 | ret = sht15_send_status(data, previous_config); | ||
542 | if (ret) { | ||
543 | dev_err(data->dev, | ||
544 | "CRC validation failed, unable " | ||
545 | "to restore device settings\n"); | ||
546 | return ret; | ||
547 | } | ||
548 | } | ||
549 | return -EAGAIN; | ||
550 | } | ||
551 | |||
398 | return 0; | 552 | return 0; |
399 | } | 553 | } |
400 | 554 | ||
@@ -635,28 +789,11 @@ static irqreturn_t sht15_interrupt_fired(int irq, void *d) | |||
635 | return IRQ_HANDLED; | 789 | return IRQ_HANDLED; |
636 | } | 790 | } |
637 | 791 | ||
638 | /** | ||
639 | * sht15_ack() - Send an ack to the device | ||
640 | * | ||
641 | * Each byte of data is acknowledged by pulling the data line | ||
642 | * low for one clock pulse. | ||
643 | */ | ||
644 | static void sht15_ack(struct sht15_data *data) | ||
645 | { | ||
646 | gpio_direction_output(data->pdata->gpio_data, 0); | ||
647 | ndelay(SHT15_TSU); | ||
648 | gpio_set_value(data->pdata->gpio_sck, 1); | ||
649 | ndelay(SHT15_TSU); | ||
650 | gpio_set_value(data->pdata->gpio_sck, 0); | ||
651 | ndelay(SHT15_TSU); | ||
652 | gpio_set_value(data->pdata->gpio_data, 1); | ||
653 | |||
654 | gpio_direction_input(data->pdata->gpio_data); | ||
655 | } | ||
656 | |||
657 | static void sht15_bh_read_data(struct work_struct *work_s) | 792 | static void sht15_bh_read_data(struct work_struct *work_s) |
658 | { | 793 | { |
659 | uint16_t val = 0; | 794 | uint16_t val = 0; |
795 | u8 dev_checksum = 0; | ||
796 | u8 checksum_vals[3]; | ||
660 | struct sht15_data *data | 797 | struct sht15_data *data |
661 | = container_of(work_s, struct sht15_data, | 798 | = container_of(work_s, struct sht15_data, |
662 | read_work); | 799 | read_work); |
@@ -681,6 +818,21 @@ static void sht15_bh_read_data(struct work_struct *work_s) | |||
681 | sht15_ack(data); | 818 | sht15_ack(data); |
682 | val |= sht15_read_byte(data); | 819 | val |= sht15_read_byte(data); |
683 | 820 | ||
821 | if (data->checksumming) { | ||
822 | /* | ||
823 | * Ask the device for a checksum and read it back. | ||
824 | * Note: the device sends the checksum byte reversed. | ||
825 | */ | ||
826 | sht15_ack(data); | ||
827 | dev_checksum = sht15_reverse(sht15_read_byte(data)); | ||
828 | checksum_vals[0] = (data->state == SHT15_READING_TEMP) ? | ||
829 | SHT15_MEASURE_TEMP : SHT15_MEASURE_RH; | ||
830 | checksum_vals[1] = (u8) (val >> 8); | ||
831 | checksum_vals[2] = (u8) val; | ||
832 | data->checksum_ok | ||
833 | = (sht15_crc8(data, checksum_vals, 3) == dev_checksum); | ||
834 | } | ||
835 | |||
684 | /* Tell the device we are done */ | 836 | /* Tell the device we are done */ |
685 | sht15_end_transmission(data); | 837 | sht15_end_transmission(data); |
686 | 838 | ||
@@ -754,6 +906,8 @@ static int __devinit sht15_probe(struct platform_device *pdev) | |||
754 | } | 906 | } |
755 | data->pdata = pdev->dev.platform_data; | 907 | data->pdata = pdev->dev.platform_data; |
756 | data->supply_uV = data->pdata->supply_mv * 1000; | 908 | data->supply_uV = data->pdata->supply_mv * 1000; |
909 | if (data->pdata->checksum) | ||
910 | data->checksumming = true; | ||
757 | if (data->pdata->no_otp_reload) | 911 | if (data->pdata->no_otp_reload) |
758 | status |= SHT15_STATUS_NO_OTP_RELOAD; | 912 | status |= SHT15_STATUS_NO_OTP_RELOAD; |
759 | if (data->pdata->low_resolution) | 913 | if (data->pdata->low_resolution) |