diff options
-rw-r--r-- | drivers/media/radio/si4713/si4713.c | 108 |
1 files changed, 64 insertions, 44 deletions
diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c index 4f3308f91608..5d26b9ad014d 100644 --- a/drivers/media/radio/si4713/si4713.c +++ b/drivers/media/radio/si4713/si4713.c | |||
@@ -27,11 +27,11 @@ | |||
27 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/gpio.h> | 29 | #include <linux/gpio.h> |
30 | #include <linux/regulator/consumer.h> | ||
31 | #include <linux/module.h> | 30 | #include <linux/module.h> |
32 | #include <media/v4l2-device.h> | 31 | #include <media/v4l2-device.h> |
33 | #include <media/v4l2-ioctl.h> | 32 | #include <media/v4l2-ioctl.h> |
34 | #include <media/v4l2-common.h> | 33 | #include <media/v4l2-common.h> |
34 | #include <linux/regulator/consumer.h> | ||
35 | 35 | ||
36 | #include "si4713.h" | 36 | #include "si4713.h" |
37 | 37 | ||
@@ -213,6 +213,7 @@ static int si4713_send_command(struct si4713_device *sdev, const u8 command, | |||
213 | u8 response[], const int respn, const int usecs) | 213 | u8 response[], const int respn, const int usecs) |
214 | { | 214 | { |
215 | struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); | 215 | struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); |
216 | unsigned long until_jiffies; | ||
216 | u8 data1[MAX_ARGS + 1]; | 217 | u8 data1[MAX_ARGS + 1]; |
217 | int err; | 218 | int err; |
218 | 219 | ||
@@ -228,30 +229,39 @@ static int si4713_send_command(struct si4713_device *sdev, const u8 command, | |||
228 | if (err != argn + 1) { | 229 | if (err != argn + 1) { |
229 | v4l2_err(&sdev->sd, "Error while sending command 0x%02x\n", | 230 | v4l2_err(&sdev->sd, "Error while sending command 0x%02x\n", |
230 | command); | 231 | command); |
231 | return (err > 0) ? -EIO : err; | 232 | return err < 0 ? err : -EIO; |
232 | } | 233 | } |
233 | 234 | ||
235 | until_jiffies = jiffies + usecs_to_jiffies(usecs) + 1; | ||
236 | |||
234 | /* Wait response from interrupt */ | 237 | /* Wait response from interrupt */ |
235 | if (!wait_for_completion_timeout(&sdev->work, | 238 | if (client->irq) { |
239 | if (!wait_for_completion_timeout(&sdev->work, | ||
236 | usecs_to_jiffies(usecs) + 1)) | 240 | usecs_to_jiffies(usecs) + 1)) |
237 | v4l2_warn(&sdev->sd, | 241 | v4l2_warn(&sdev->sd, |
238 | "(%s) Device took too much time to answer.\n", | 242 | "(%s) Device took too much time to answer.\n", |
239 | __func__); | 243 | __func__); |
240 | |||
241 | /* Then get the response */ | ||
242 | err = i2c_master_recv(client, response, respn); | ||
243 | if (err != respn) { | ||
244 | v4l2_err(&sdev->sd, | ||
245 | "Error while reading response for command 0x%02x\n", | ||
246 | command); | ||
247 | return (err > 0) ? -EIO : err; | ||
248 | } | 244 | } |
249 | 245 | ||
250 | DBG_BUFFER(&sdev->sd, "Response", response, respn); | 246 | do { |
251 | if (check_command_failed(response[0])) | 247 | err = i2c_master_recv(client, response, respn); |
252 | return -EBUSY; | 248 | if (err != respn) { |
249 | v4l2_err(&sdev->sd, | ||
250 | "Error %d while reading response for command 0x%02x\n", | ||
251 | err, command); | ||
252 | return err < 0 ? err : -EIO; | ||
253 | } | ||
254 | |||
255 | DBG_BUFFER(&sdev->sd, "Response", response, respn); | ||
256 | if (!check_command_failed(response[0])) | ||
257 | return 0; | ||
253 | 258 | ||
254 | return 0; | 259 | if (client->irq) |
260 | return -EBUSY; | ||
261 | msleep(1); | ||
262 | } while (jiffies <= until_jiffies); | ||
263 | |||
264 | return -EBUSY; | ||
255 | } | 265 | } |
256 | 266 | ||
257 | /* | 267 | /* |
@@ -344,14 +354,15 @@ static int si4713_write_property(struct si4713_device *sdev, u16 prop, u16 val) | |||
344 | */ | 354 | */ |
345 | static int si4713_powerup(struct si4713_device *sdev) | 355 | static int si4713_powerup(struct si4713_device *sdev) |
346 | { | 356 | { |
357 | struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); | ||
347 | int err; | 358 | int err; |
348 | u8 resp[SI4713_PWUP_NRESP]; | 359 | u8 resp[SI4713_PWUP_NRESP]; |
349 | /* | 360 | /* |
350 | * .First byte = Enabled interrupts and boot function | 361 | * .First byte = Enabled interrupts and boot function |
351 | * .Second byte = Input operation mode | 362 | * .Second byte = Input operation mode |
352 | */ | 363 | */ |
353 | const u8 args[SI4713_PWUP_NARGS] = { | 364 | u8 args[SI4713_PWUP_NARGS] = { |
354 | SI4713_PWUP_CTSIEN | SI4713_PWUP_GPO2OEN | SI4713_PWUP_FUNC_TX, | 365 | SI4713_PWUP_GPO2OEN | SI4713_PWUP_FUNC_TX, |
355 | SI4713_PWUP_OPMOD_ANALOG, | 366 | SI4713_PWUP_OPMOD_ANALOG, |
356 | }; | 367 | }; |
357 | 368 | ||
@@ -369,6 +380,9 @@ static int si4713_powerup(struct si4713_device *sdev) | |||
369 | gpio_set_value(sdev->gpio_reset, 1); | 380 | gpio_set_value(sdev->gpio_reset, 1); |
370 | } | 381 | } |
371 | 382 | ||
383 | if (client->irq) | ||
384 | args[0] |= SI4713_PWUP_CTSIEN; | ||
385 | |||
372 | err = si4713_send_command(sdev, SI4713_CMD_POWER_UP, | 386 | err = si4713_send_command(sdev, SI4713_CMD_POWER_UP, |
373 | args, ARRAY_SIZE(args), | 387 | args, ARRAY_SIZE(args), |
374 | resp, ARRAY_SIZE(resp), | 388 | resp, ARRAY_SIZE(resp), |
@@ -380,7 +394,8 @@ static int si4713_powerup(struct si4713_device *sdev) | |||
380 | v4l2_dbg(1, debug, &sdev->sd, "Device in power up mode\n"); | 394 | v4l2_dbg(1, debug, &sdev->sd, "Device in power up mode\n"); |
381 | sdev->power_state = POWER_ON; | 395 | sdev->power_state = POWER_ON; |
382 | 396 | ||
383 | err = si4713_write_property(sdev, SI4713_GPO_IEN, | 397 | if (client->irq) |
398 | err = si4713_write_property(sdev, SI4713_GPO_IEN, | ||
384 | SI4713_STC_INT | SI4713_CTS); | 399 | SI4713_STC_INT | SI4713_CTS); |
385 | } else { | 400 | } else { |
386 | if (gpio_is_valid(sdev->gpio_reset)) | 401 | if (gpio_is_valid(sdev->gpio_reset)) |
@@ -465,33 +480,39 @@ static int si4713_checkrev(struct si4713_device *sdev) | |||
465 | */ | 480 | */ |
466 | static int si4713_wait_stc(struct si4713_device *sdev, const int usecs) | 481 | static int si4713_wait_stc(struct si4713_device *sdev, const int usecs) |
467 | { | 482 | { |
468 | int err; | 483 | struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd); |
469 | u8 resp[SI4713_GET_STATUS_NRESP]; | 484 | u8 resp[SI4713_GET_STATUS_NRESP]; |
485 | unsigned long start_jiffies = jiffies; | ||
486 | int err; | ||
470 | 487 | ||
471 | /* Wait response from STC interrupt */ | 488 | if (client->irq && |
472 | if (!wait_for_completion_timeout(&sdev->work, | 489 | !wait_for_completion_timeout(&sdev->work, usecs_to_jiffies(usecs) + 1)) |
473 | usecs_to_jiffies(usecs) + 1)) | ||
474 | v4l2_warn(&sdev->sd, | 490 | v4l2_warn(&sdev->sd, |
475 | "%s: device took too much time to answer (%d usec).\n", | 491 | "(%s) Device took too much time to answer.\n", __func__); |
476 | __func__, usecs); | 492 | |
477 | 493 | for (;;) { | |
478 | /* Clear status bits */ | 494 | /* Clear status bits */ |
479 | err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS, | 495 | err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS, |
480 | NULL, 0, | 496 | NULL, 0, |
481 | resp, ARRAY_SIZE(resp), | 497 | resp, ARRAY_SIZE(resp), |
482 | DEFAULT_TIMEOUT); | 498 | DEFAULT_TIMEOUT); |
483 | 499 | /* The USB device returns errors when it waits for the | |
484 | if (err < 0) | 500 | * STC bit to be set. Hence polling */ |
485 | goto exit; | 501 | if (err >= 0) { |
486 | 502 | v4l2_dbg(1, debug, &sdev->sd, | |
487 | v4l2_dbg(1, debug, &sdev->sd, | 503 | "%s: status bits: 0x%02x\n", __func__, resp[0]); |
488 | "%s: status bits: 0x%02x\n", __func__, resp[0]); | 504 | |
489 | 505 | if (resp[0] & SI4713_STC_INT) | |
490 | if (!(resp[0] & SI4713_STC_INT)) | 506 | return 0; |
491 | err = -EIO; | 507 | } |
492 | 508 | if (jiffies_to_usecs(jiffies - start_jiffies) > usecs) | |
493 | exit: | 509 | return err < 0 ? err : -EIO; |
494 | return err; | 510 | /* We sleep here for 3 ms in order to avoid flooding the device |
511 | * with USB requests. The si4713 USB driver was developed | ||
512 | * by reverse engineering the Windows USB driver. The windows | ||
513 | * driver also has a ~2.5 ms delay between responses. */ | ||
514 | msleep(3); | ||
515 | } | ||
495 | } | 516 | } |
496 | 517 | ||
497 | /* | 518 | /* |
@@ -1024,7 +1045,6 @@ static int si4713_initialize(struct si4713_device *sdev) | |||
1024 | if (rval < 0) | 1045 | if (rval < 0) |
1025 | return rval; | 1046 | return rval; |
1026 | 1047 | ||
1027 | |||
1028 | sdev->frequency = DEFAULT_FREQUENCY; | 1048 | sdev->frequency = DEFAULT_FREQUENCY; |
1029 | sdev->stereo = 1; | 1049 | sdev->stereo = 1; |
1030 | sdev->tune_rnl = DEFAULT_TUNE_RNL; | 1050 | sdev->tune_rnl = DEFAULT_TUNE_RNL; |