diff options
author | Vivien Didelot <vivien.didelot@savoirfairelinux.com> | 2013-01-15 13:33:06 -0500 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2013-02-06 12:57:55 -0500 |
commit | 412e29c135c11be6e2e4b22c0691e861b3d946c4 (patch) | |
tree | 629d7e08a4ae41b6f1814115ac6af1df3d0945f7 /drivers/hwmon | |
parent | 9e3970fba9ea43bc2c215f71f78bcf766c1775e7 (diff) |
hwmon: (sht15) check GPIO directions
Without this patch, the SHT15 driver may fail silently with a
non-bidirectional data line and/or an input-only clock line.
This patch checks the return value of gpio_direction_* function calls
and returns the error code (if any) to the caller. If an error occurs in
the read work function (work_funct_t), we wake the queue up directly
without updating the data->state flag, to notice the waiter of the I/O
error.
The patch also makes minor cleanups: s/error_ret/unlock for some labels
and uses devm_gpio_request_one() for the clock line.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/sht15.c | 135 |
1 files changed, 88 insertions, 47 deletions
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 9a594e6533a9..bfe326e896df 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c | |||
@@ -212,11 +212,13 @@ static u8 sht15_crc8(struct sht15_data *data, | |||
212 | * | 212 | * |
213 | * This implements section 3.4 of the data sheet | 213 | * This implements section 3.4 of the data sheet |
214 | */ | 214 | */ |
215 | static void sht15_connection_reset(struct sht15_data *data) | 215 | static int sht15_connection_reset(struct sht15_data *data) |
216 | { | 216 | { |
217 | int i; | 217 | int i, err; |
218 | 218 | ||
219 | gpio_direction_output(data->pdata->gpio_data, 1); | 219 | err = gpio_direction_output(data->pdata->gpio_data, 1); |
220 | if (err) | ||
221 | return err; | ||
220 | ndelay(SHT15_TSCKL); | 222 | ndelay(SHT15_TSCKL); |
221 | gpio_set_value(data->pdata->gpio_sck, 0); | 223 | gpio_set_value(data->pdata->gpio_sck, 0); |
222 | ndelay(SHT15_TSCKL); | 224 | ndelay(SHT15_TSCKL); |
@@ -226,6 +228,7 @@ static void sht15_connection_reset(struct sht15_data *data) | |||
226 | gpio_set_value(data->pdata->gpio_sck, 0); | 228 | gpio_set_value(data->pdata->gpio_sck, 0); |
227 | ndelay(SHT15_TSCKL); | 229 | ndelay(SHT15_TSCKL); |
228 | } | 230 | } |
231 | return 0; | ||
229 | } | 232 | } |
230 | 233 | ||
231 | /** | 234 | /** |
@@ -251,10 +254,14 @@ static inline void sht15_send_bit(struct sht15_data *data, int val) | |||
251 | * conservative ones used in implementation. This implements | 254 | * conservative ones used in implementation. This implements |
252 | * figure 12 on the data sheet. | 255 | * figure 12 on the data sheet. |
253 | */ | 256 | */ |
254 | static void sht15_transmission_start(struct sht15_data *data) | 257 | static int sht15_transmission_start(struct sht15_data *data) |
255 | { | 258 | { |
259 | int err; | ||
260 | |||
256 | /* ensure data is high and output */ | 261 | /* ensure data is high and output */ |
257 | gpio_direction_output(data->pdata->gpio_data, 1); | 262 | err = gpio_direction_output(data->pdata->gpio_data, 1); |
263 | if (err) | ||
264 | return err; | ||
258 | ndelay(SHT15_TSU); | 265 | ndelay(SHT15_TSU); |
259 | gpio_set_value(data->pdata->gpio_sck, 0); | 266 | gpio_set_value(data->pdata->gpio_sck, 0); |
260 | ndelay(SHT15_TSCKL); | 267 | ndelay(SHT15_TSCKL); |
@@ -270,6 +277,7 @@ static void sht15_transmission_start(struct sht15_data *data) | |||
270 | ndelay(SHT15_TSU); | 277 | ndelay(SHT15_TSU); |
271 | gpio_set_value(data->pdata->gpio_sck, 0); | 278 | gpio_set_value(data->pdata->gpio_sck, 0); |
272 | ndelay(SHT15_TSCKL); | 279 | ndelay(SHT15_TSCKL); |
280 | return 0; | ||
273 | } | 281 | } |
274 | 282 | ||
275 | /** | 283 | /** |
@@ -293,13 +301,19 @@ static void sht15_send_byte(struct sht15_data *data, u8 byte) | |||
293 | */ | 301 | */ |
294 | static int sht15_wait_for_response(struct sht15_data *data) | 302 | static int sht15_wait_for_response(struct sht15_data *data) |
295 | { | 303 | { |
296 | gpio_direction_input(data->pdata->gpio_data); | 304 | int err; |
305 | |||
306 | err = gpio_direction_input(data->pdata->gpio_data); | ||
307 | if (err) | ||
308 | return err; | ||
297 | gpio_set_value(data->pdata->gpio_sck, 1); | 309 | gpio_set_value(data->pdata->gpio_sck, 1); |
298 | ndelay(SHT15_TSCKH); | 310 | ndelay(SHT15_TSCKH); |
299 | if (gpio_get_value(data->pdata->gpio_data)) { | 311 | if (gpio_get_value(data->pdata->gpio_data)) { |
300 | gpio_set_value(data->pdata->gpio_sck, 0); | 312 | gpio_set_value(data->pdata->gpio_sck, 0); |
301 | dev_err(data->dev, "Command not acknowledged\n"); | 313 | dev_err(data->dev, "Command not acknowledged\n"); |
302 | sht15_connection_reset(data); | 314 | err = sht15_connection_reset(data); |
315 | if (err) | ||
316 | return err; | ||
303 | return -EIO; | 317 | return -EIO; |
304 | } | 318 | } |
305 | gpio_set_value(data->pdata->gpio_sck, 0); | 319 | gpio_set_value(data->pdata->gpio_sck, 0); |
@@ -317,12 +331,13 @@ static int sht15_wait_for_response(struct sht15_data *data) | |||
317 | */ | 331 | */ |
318 | static int sht15_send_cmd(struct sht15_data *data, u8 cmd) | 332 | static int sht15_send_cmd(struct sht15_data *data, u8 cmd) |
319 | { | 333 | { |
320 | int ret = 0; | 334 | int err; |
321 | 335 | ||
322 | sht15_transmission_start(data); | 336 | err = sht15_transmission_start(data); |
337 | if (err) | ||
338 | return err; | ||
323 | sht15_send_byte(data, cmd); | 339 | sht15_send_byte(data, cmd); |
324 | ret = sht15_wait_for_response(data); | 340 | return sht15_wait_for_response(data); |
325 | return ret; | ||
326 | } | 341 | } |
327 | 342 | ||
328 | /** | 343 | /** |
@@ -352,9 +367,13 @@ static int sht15_soft_reset(struct sht15_data *data) | |||
352 | * Each byte of data is acknowledged by pulling the data line | 367 | * Each byte of data is acknowledged by pulling the data line |
353 | * low for one clock pulse. | 368 | * low for one clock pulse. |
354 | */ | 369 | */ |
355 | static void sht15_ack(struct sht15_data *data) | 370 | static int sht15_ack(struct sht15_data *data) |
356 | { | 371 | { |
357 | gpio_direction_output(data->pdata->gpio_data, 0); | 372 | int err; |
373 | |||
374 | err = gpio_direction_output(data->pdata->gpio_data, 0); | ||
375 | if (err) | ||
376 | return err; | ||
358 | ndelay(SHT15_TSU); | 377 | ndelay(SHT15_TSU); |
359 | gpio_set_value(data->pdata->gpio_sck, 1); | 378 | gpio_set_value(data->pdata->gpio_sck, 1); |
360 | ndelay(SHT15_TSU); | 379 | ndelay(SHT15_TSU); |
@@ -362,7 +381,7 @@ static void sht15_ack(struct sht15_data *data) | |||
362 | ndelay(SHT15_TSU); | 381 | ndelay(SHT15_TSU); |
363 | gpio_set_value(data->pdata->gpio_data, 1); | 382 | gpio_set_value(data->pdata->gpio_data, 1); |
364 | 383 | ||
365 | gpio_direction_input(data->pdata->gpio_data); | 384 | return gpio_direction_input(data->pdata->gpio_data); |
366 | } | 385 | } |
367 | 386 | ||
368 | /** | 387 | /** |
@@ -371,14 +390,19 @@ static void sht15_ack(struct sht15_data *data) | |||
371 | * | 390 | * |
372 | * This is basically a NAK (single clock pulse, data high). | 391 | * This is basically a NAK (single clock pulse, data high). |
373 | */ | 392 | */ |
374 | static void sht15_end_transmission(struct sht15_data *data) | 393 | static int sht15_end_transmission(struct sht15_data *data) |
375 | { | 394 | { |
376 | gpio_direction_output(data->pdata->gpio_data, 1); | 395 | int err; |
396 | |||
397 | err = gpio_direction_output(data->pdata->gpio_data, 1); | ||
398 | if (err) | ||
399 | return err; | ||
377 | ndelay(SHT15_TSU); | 400 | ndelay(SHT15_TSU); |
378 | gpio_set_value(data->pdata->gpio_sck, 1); | 401 | gpio_set_value(data->pdata->gpio_sck, 1); |
379 | ndelay(SHT15_TSCKH); | 402 | ndelay(SHT15_TSCKH); |
380 | gpio_set_value(data->pdata->gpio_sck, 0); | 403 | gpio_set_value(data->pdata->gpio_sck, 0); |
381 | ndelay(SHT15_TSCKL); | 404 | ndelay(SHT15_TSCKL); |
405 | return 0; | ||
382 | } | 406 | } |
383 | 407 | ||
384 | /** | 408 | /** |
@@ -410,17 +434,19 @@ static u8 sht15_read_byte(struct sht15_data *data) | |||
410 | */ | 434 | */ |
411 | static int sht15_send_status(struct sht15_data *data, u8 status) | 435 | static int sht15_send_status(struct sht15_data *data, u8 status) |
412 | { | 436 | { |
413 | int ret; | 437 | int err; |
414 | 438 | ||
415 | ret = sht15_send_cmd(data, SHT15_WRITE_STATUS); | 439 | err = sht15_send_cmd(data, SHT15_WRITE_STATUS); |
416 | if (ret) | 440 | if (err) |
417 | return ret; | 441 | return err; |
418 | gpio_direction_output(data->pdata->gpio_data, 1); | 442 | err = gpio_direction_output(data->pdata->gpio_data, 1); |
443 | if (err) | ||
444 | return err; | ||
419 | ndelay(SHT15_TSU); | 445 | ndelay(SHT15_TSU); |
420 | sht15_send_byte(data, status); | 446 | sht15_send_byte(data, status); |
421 | ret = sht15_wait_for_response(data); | 447 | err = sht15_wait_for_response(data); |
422 | if (ret) | 448 | if (err) |
423 | return ret; | 449 | return err; |
424 | 450 | ||
425 | data->val_status = status; | 451 | data->val_status = status; |
426 | return 0; | 452 | return 0; |
@@ -446,7 +472,7 @@ static int sht15_update_status(struct sht15_data *data) | |||
446 | || !data->status_valid) { | 472 | || !data->status_valid) { |
447 | ret = sht15_send_cmd(data, SHT15_READ_STATUS); | 473 | ret = sht15_send_cmd(data, SHT15_READ_STATUS); |
448 | if (ret) | 474 | if (ret) |
449 | goto error_ret; | 475 | goto unlock; |
450 | status = sht15_read_byte(data); | 476 | status = sht15_read_byte(data); |
451 | 477 | ||
452 | if (data->checksumming) { | 478 | if (data->checksumming) { |
@@ -458,7 +484,9 @@ static int sht15_update_status(struct sht15_data *data) | |||
458 | == dev_checksum); | 484 | == dev_checksum); |
459 | } | 485 | } |
460 | 486 | ||
461 | sht15_end_transmission(data); | 487 | ret = sht15_end_transmission(data); |
488 | if (ret) | ||
489 | goto unlock; | ||
462 | 490 | ||
463 | /* | 491 | /* |
464 | * Perform checksum validation on the received data. | 492 | * Perform checksum validation on the received data. |
@@ -469,27 +497,27 @@ static int sht15_update_status(struct sht15_data *data) | |||
469 | previous_config = data->val_status & 0x07; | 497 | previous_config = data->val_status & 0x07; |
470 | ret = sht15_soft_reset(data); | 498 | ret = sht15_soft_reset(data); |
471 | if (ret) | 499 | if (ret) |
472 | goto error_ret; | 500 | goto unlock; |
473 | if (previous_config) { | 501 | if (previous_config) { |
474 | ret = sht15_send_status(data, previous_config); | 502 | ret = sht15_send_status(data, previous_config); |
475 | if (ret) { | 503 | if (ret) { |
476 | dev_err(data->dev, | 504 | dev_err(data->dev, |
477 | "CRC validation failed, unable " | 505 | "CRC validation failed, unable " |
478 | "to restore device settings\n"); | 506 | "to restore device settings\n"); |
479 | goto error_ret; | 507 | goto unlock; |
480 | } | 508 | } |
481 | } | 509 | } |
482 | ret = -EAGAIN; | 510 | ret = -EAGAIN; |
483 | goto error_ret; | 511 | goto unlock; |
484 | } | 512 | } |
485 | 513 | ||
486 | data->val_status = status; | 514 | data->val_status = status; |
487 | data->status_valid = true; | 515 | data->status_valid = true; |
488 | data->last_status = jiffies; | 516 | data->last_status = jiffies; |
489 | } | 517 | } |
490 | error_ret: | ||
491 | mutex_unlock(&data->read_lock); | ||
492 | 518 | ||
519 | unlock: | ||
520 | mutex_unlock(&data->read_lock); | ||
493 | return ret; | 521 | return ret; |
494 | } | 522 | } |
495 | 523 | ||
@@ -511,7 +539,9 @@ static int sht15_measurement(struct sht15_data *data, | |||
511 | if (ret) | 539 | if (ret) |
512 | return ret; | 540 | return ret; |
513 | 541 | ||
514 | gpio_direction_input(data->pdata->gpio_data); | 542 | ret = gpio_direction_input(data->pdata->gpio_data); |
543 | if (ret) | ||
544 | return ret; | ||
515 | atomic_set(&data->interrupt_handled, 0); | 545 | atomic_set(&data->interrupt_handled, 0); |
516 | 546 | ||
517 | enable_irq(gpio_to_irq(data->pdata->gpio_data)); | 547 | enable_irq(gpio_to_irq(data->pdata->gpio_data)); |
@@ -524,9 +554,14 @@ static int sht15_measurement(struct sht15_data *data, | |||
524 | ret = wait_event_timeout(data->wait_queue, | 554 | ret = wait_event_timeout(data->wait_queue, |
525 | (data->state == SHT15_READING_NOTHING), | 555 | (data->state == SHT15_READING_NOTHING), |
526 | msecs_to_jiffies(timeout_msecs)); | 556 | msecs_to_jiffies(timeout_msecs)); |
527 | if (ret == 0) {/* timeout occurred */ | 557 | if (data->state != SHT15_READING_NOTHING) { /* I/O error occurred */ |
558 | data->state = SHT15_READING_NOTHING; | ||
559 | return -EIO; | ||
560 | } else if (ret == 0) { /* timeout occurred */ | ||
528 | disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data)); | 561 | disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data)); |
529 | sht15_connection_reset(data); | 562 | ret = sht15_connection_reset(data); |
563 | if (ret) | ||
564 | return ret; | ||
530 | return -ETIME; | 565 | return -ETIME; |
531 | } | 566 | } |
532 | 567 | ||
@@ -570,17 +605,17 @@ static int sht15_update_measurements(struct sht15_data *data) | |||
570 | data->state = SHT15_READING_HUMID; | 605 | data->state = SHT15_READING_HUMID; |
571 | ret = sht15_measurement(data, SHT15_MEASURE_RH, 160); | 606 | ret = sht15_measurement(data, SHT15_MEASURE_RH, 160); |
572 | if (ret) | 607 | if (ret) |
573 | goto error_ret; | 608 | goto unlock; |
574 | data->state = SHT15_READING_TEMP; | 609 | data->state = SHT15_READING_TEMP; |
575 | ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400); | 610 | ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400); |
576 | if (ret) | 611 | if (ret) |
577 | goto error_ret; | 612 | goto unlock; |
578 | data->measurements_valid = true; | 613 | data->measurements_valid = true; |
579 | data->last_measurement = jiffies; | 614 | data->last_measurement = jiffies; |
580 | } | 615 | } |
581 | error_ret: | ||
582 | mutex_unlock(&data->read_lock); | ||
583 | 616 | ||
617 | unlock: | ||
618 | mutex_unlock(&data->read_lock); | ||
584 | return ret; | 619 | return ret; |
585 | } | 620 | } |
586 | 621 | ||
@@ -818,7 +853,8 @@ static void sht15_bh_read_data(struct work_struct *work_s) | |||
818 | /* Read the data back from the device */ | 853 | /* Read the data back from the device */ |
819 | val = sht15_read_byte(data); | 854 | val = sht15_read_byte(data); |
820 | val <<= 8; | 855 | val <<= 8; |
821 | sht15_ack(data); | 856 | if (sht15_ack(data)) |
857 | goto wakeup; | ||
822 | val |= sht15_read_byte(data); | 858 | val |= sht15_read_byte(data); |
823 | 859 | ||
824 | if (data->checksumming) { | 860 | if (data->checksumming) { |
@@ -826,7 +862,8 @@ static void sht15_bh_read_data(struct work_struct *work_s) | |||
826 | * Ask the device for a checksum and read it back. | 862 | * Ask the device for a checksum and read it back. |
827 | * Note: the device sends the checksum byte reversed. | 863 | * Note: the device sends the checksum byte reversed. |
828 | */ | 864 | */ |
829 | sht15_ack(data); | 865 | if (sht15_ack(data)) |
866 | goto wakeup; | ||
830 | dev_checksum = sht15_reverse(sht15_read_byte(data)); | 867 | dev_checksum = sht15_reverse(sht15_read_byte(data)); |
831 | checksum_vals[0] = (data->state == SHT15_READING_TEMP) ? | 868 | checksum_vals[0] = (data->state == SHT15_READING_TEMP) ? |
832 | SHT15_MEASURE_TEMP : SHT15_MEASURE_RH; | 869 | SHT15_MEASURE_TEMP : SHT15_MEASURE_RH; |
@@ -837,7 +874,8 @@ static void sht15_bh_read_data(struct work_struct *work_s) | |||
837 | } | 874 | } |
838 | 875 | ||
839 | /* Tell the device we are done */ | 876 | /* Tell the device we are done */ |
840 | sht15_end_transmission(data); | 877 | if (sht15_end_transmission(data)) |
878 | goto wakeup; | ||
841 | 879 | ||
842 | switch (data->state) { | 880 | switch (data->state) { |
843 | case SHT15_READING_TEMP: | 881 | case SHT15_READING_TEMP: |
@@ -851,6 +889,7 @@ static void sht15_bh_read_data(struct work_struct *work_s) | |||
851 | } | 889 | } |
852 | 890 | ||
853 | data->state = SHT15_READING_NOTHING; | 891 | data->state = SHT15_READING_NOTHING; |
892 | wakeup: | ||
854 | wake_up(&data->wait_queue); | 893 | wake_up(&data->wait_queue); |
855 | } | 894 | } |
856 | 895 | ||
@@ -942,17 +981,17 @@ static int sht15_probe(struct platform_device *pdev) | |||
942 | } | 981 | } |
943 | 982 | ||
944 | /* Try requesting the GPIOs */ | 983 | /* Try requesting the GPIOs */ |
945 | ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_sck, "SHT15 sck"); | 984 | ret = devm_gpio_request_one(&pdev->dev, data->pdata->gpio_sck, |
985 | GPIOF_OUT_INIT_LOW, "SHT15 sck"); | ||
946 | if (ret) { | 986 | if (ret) { |
947 | dev_err(&pdev->dev, "gpio request failed\n"); | 987 | dev_err(&pdev->dev, "clock line GPIO request failed\n"); |
948 | goto err_release_reg; | 988 | goto err_release_reg; |
949 | } | 989 | } |
950 | gpio_direction_output(data->pdata->gpio_sck, 0); | ||
951 | 990 | ||
952 | ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data, | 991 | ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data, |
953 | "SHT15 data"); | 992 | "SHT15 data"); |
954 | if (ret) { | 993 | if (ret) { |
955 | dev_err(&pdev->dev, "gpio request failed\n"); | 994 | dev_err(&pdev->dev, "data line GPIO request failed\n"); |
956 | goto err_release_reg; | 995 | goto err_release_reg; |
957 | } | 996 | } |
958 | 997 | ||
@@ -966,7 +1005,9 @@ static int sht15_probe(struct platform_device *pdev) | |||
966 | goto err_release_reg; | 1005 | goto err_release_reg; |
967 | } | 1006 | } |
968 | disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data)); | 1007 | disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data)); |
969 | sht15_connection_reset(data); | 1008 | ret = sht15_connection_reset(data); |
1009 | if (ret) | ||
1010 | goto err_release_reg; | ||
970 | ret = sht15_soft_reset(data); | 1011 | ret = sht15_soft_reset(data); |
971 | if (ret) | 1012 | if (ret) |
972 | goto err_release_reg; | 1013 | goto err_release_reg; |