V4L/DVB (13442): ivtv: Add module parameter to adjust I2C SCL clock period per board
authorAndy Walls <awalls@radix.net>
Sat, 21 Nov 2009 04:47:45 +0000 (01:47 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Sat, 5 Dec 2009 20:41:55 +0000 (18:41 -0200)
Add a module parameter to adjust I2C SCL clock period per board.  This allows
some experimental fine tuning by end users to overcome quirky I2C device
problems.

Reported-by: "Aleksandr V. Piskunov" <aleksandr.v.piskunov@gmail.com>
Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-i2c.c

index 7cdbc1a8f218b361bced0ee06dc637f2c925717a..8330fb5c7eb33e05c02dad4587f950d4b937116c 100644 (file)
@@ -91,10 +91,15 @@ static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1 };
+static int i2c_clock_period[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+                                              -1, -1, -1, -1, -1, -1, -1, -1,
+                                              -1, -1, -1, -1, -1, -1, -1, -1,
+                                              -1, -1, -1, -1, -1, -1, -1, -1 };
 
 static unsigned int cardtype_c = 1;
 static unsigned int tuner_c = 1;
 static unsigned int radio_c = 1;
+static unsigned int i2c_clock_period_c = 1;
 static char pal[] = "---";
 static char secam[] = "--";
 static char ntsc[] = "-";
@@ -151,6 +156,7 @@ module_param(dec_vbi_buffers, int, 0644);
 
 module_param(tunertype, int, 0644);
 module_param(newi2c, int, 0644);
+module_param_array(i2c_clock_period, int, &i2c_clock_period_c, 0644);
 
 MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
                        "\t\t\tsee tuner.h for values");
@@ -245,6 +251,10 @@ MODULE_PARM_DESC(newi2c,
                 "Use new I2C implementation\n"
                 "\t\t\t-1 is autodetect, 0 is off, 1 is on\n"
                 "\t\t\tDefault is autodetect");
+MODULE_PARM_DESC(i2c_clock_period,
+                "Period of SCL for the I2C bus controlled by the CX23415/6\n"
+                "\t\t\tMin: 10 usec (100 kHz), Max: 4500 usec (222 Hz)\n"
+                "\t\t\tDefault: " __stringify(IVTV_DEFAULT_I2C_CLOCK_PERIOD));
 
 MODULE_PARM_DESC(ivtv_first_minor, "Set device node number assigned to first card");
 
@@ -600,6 +610,15 @@ static void ivtv_process_options(struct ivtv *itv)
        itv->options.cardtype = cardtype[itv->instance];
        itv->options.tuner = tuner[itv->instance];
        itv->options.radio = radio[itv->instance];
+
+       itv->options.i2c_clock_period = i2c_clock_period[itv->instance];
+       if (itv->options.i2c_clock_period == -1)
+               itv->options.i2c_clock_period = IVTV_DEFAULT_I2C_CLOCK_PERIOD;
+       else if (itv->options.i2c_clock_period < 10)
+               itv->options.i2c_clock_period = 10;
+       else if (itv->options.i2c_clock_period > 4500)
+               itv->options.i2c_clock_period = 4500;
+
        itv->options.newi2c = newi2c;
        if (tunertype < -1 || tunertype > 1) {
                IVTV_WARN("Invalid tunertype argument, will autodetect instead\n");
index 440f7328a7eda1aacb6bb1416f7c58718572d87d..2b3db90afb749884711821c9f8b1441efaf0c2c8 100644 (file)
@@ -176,12 +176,16 @@ extern int ivtv_debug;
 
 #define IVTV_MAX_PGM_INDEX (400)
 
+/* Default I2C SCL period in microseconds */
+#define IVTV_DEFAULT_I2C_CLOCK_PERIOD  20
+
 struct ivtv_options {
        int kilobytes[IVTV_MAX_STREAMS];        /* size in kilobytes of each stream */
        int cardtype;                           /* force card type on load */
        int tuner;                              /* set tuner on load */
        int radio;                              /* enable/disable radio */
        int newi2c;                             /* new I2C algorithm */
+       int i2c_clock_period;                   /* period of SCL for I2C bus */
 };
 
 /* ivtv-specific mailbox template */
index b9c71e61f7d622909dfcc431ef4369749814d578..d4cc3365038e8189ed7627edfff00088fd294785 100644 (file)
@@ -564,13 +564,15 @@ static struct i2c_adapter ivtv_i2c_adap_template = {
        .owner = THIS_MODULE,
 };
 
+#define IVTV_ALGO_BIT_TIMEOUT  (2)     /* seconds */
+
 static const struct i2c_algo_bit_data ivtv_i2c_algo_template = {
        .setsda         = ivtv_setsda_old,
        .setscl         = ivtv_setscl_old,
        .getsda         = ivtv_getsda_old,
        .getscl         = ivtv_getscl_old,
-       .udelay         = 10,
-       .timeout        = 200,
+       .udelay         = IVTV_DEFAULT_I2C_CLOCK_PERIOD / 2,  /* microseconds */
+       .timeout        = IVTV_ALGO_BIT_TIMEOUT * HZ,         /* jiffies */
 };
 
 static struct i2c_client ivtv_i2c_client_template = {
@@ -602,6 +604,7 @@ int init_ivtv_i2c(struct ivtv *itv)
                memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template,
                       sizeof(struct i2c_algo_bit_data));
        }
+       itv->i2c_algo.udelay = itv->options.i2c_clock_period / 2;
        itv->i2c_algo.data = itv;
        itv->i2c_adap.algo_data = &itv->i2c_algo;