aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/radio
diff options
context:
space:
mode:
authorDinesh Ram <Dinesh.Ram@cern.ch>2013-10-15 11:24:38 -0400
committerMauro Carvalho Chehab <m.chehab@samsung.com>2013-12-18 03:35:14 -0500
commit5173332c1e420d49829bd7e4bc5c83b0205037c5 (patch)
tree7c6508b8f65df448af2f1f4f019f40b85c31611f /drivers/media/radio
parent7391232e1215b3583de86af6e942aaa5c5c9fa97 (diff)
[media] si4713: Modified i2c driver to handle cases where interrupts are not used
Checks have been introduced at several places in the code to test if an interrupt is set or not. For devices which do not use the interrupt, to get a valid response, within a specified timeout, the device is polled instead. Signed-off-by: Dinesh Ram <dinesh.ram@cern.ch> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Tested-by: Eduardo Valentin <edubezval@gmail.com> Acked-by: Eduardo Valentin <edubezval@gmail.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/radio')
-rw-r--r--drivers/media/radio/si4713/si4713.c108
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 */
345static int si4713_powerup(struct si4713_device *sdev) 355static 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 */
466static int si4713_wait_stc(struct si4713_device *sdev, const int usecs) 481static 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)
493exit: 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;