Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu
[pandora-kernel.git] / drivers / media / radio / si470x / radio-si470x-i2c.c
index 4ce541a..a2a6777 100644 (file)
@@ -197,8 +197,9 @@ int si470x_fops_open(struct file *file)
                if (retval < 0)
                        goto done;
 
-               /* enable RDS interrupt */
+               /* enable RDS / STC interrupt */
                radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN;
+               radio->registers[SYSCONFIG1] |= SYSCONFIG1_STCIEN;
                radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2;
                radio->registers[SYSCONFIG1] |= 0x1 << 2;
                retval = si470x_set_register(radio, SYSCONFIG1);
@@ -261,12 +262,11 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
  **************************************************************************/
 
 /*
- * si470x_i2c_interrupt_work - rds processing function
+ * si470x_i2c_interrupt - interrupt handler
  */
-static void si470x_i2c_interrupt_work(struct work_struct *work)
+static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id)
 {
-       struct si470x_device *radio = container_of(work,
-                       struct si470x_device, radio_work);
+       struct si470x_device *radio = dev_id;
        unsigned char regnr;
        unsigned char blocknum;
        unsigned short bler; /* rds block errors */
@@ -274,21 +274,29 @@ static void si470x_i2c_interrupt_work(struct work_struct *work)
        unsigned char tmpbuf[3];
        int retval = 0;
 
+       /* check Seek/Tune Complete */
+       retval = si470x_get_register(radio, STATUSRSSI);
+       if (retval < 0)
+               goto end;
+
+       if (radio->registers[STATUSRSSI] & STATUSRSSI_STC)
+               complete(&radio->completion);
+
        /* safety checks */
        if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
-               return;
+               goto end;
 
        /* Update RDS registers */
-       for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) {
+       for (regnr = 1; regnr < RDS_REGISTER_NUM; regnr++) {
                retval = si470x_get_register(radio, STATUSRSSI + regnr);
                if (retval < 0)
-                       return;
+                       goto end;
        }
 
        /* get rds blocks */
        if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0)
                /* No RDS group ready, better luck next time */
-               return;
+               goto end;
 
        for (blocknum = 0; blocknum < 4; blocknum++) {
                switch (blocknum) {
@@ -342,19 +350,8 @@ static void si470x_i2c_interrupt_work(struct work_struct *work)
 
        if (radio->wr_index != radio->rd_index)
                wake_up_interruptible(&radio->read_queue);
-}
-
-
-/*
- * si470x_i2c_interrupt - interrupt handler
- */
-static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id)
-{
-       struct si470x_device *radio = dev_id;
-
-       if (!work_pending(&radio->radio_work))
-               schedule_work(&radio->radio_work);
 
+end:
        return IRQ_HANDLED;
 }
 
@@ -376,7 +373,6 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
                goto err_initial;
        }
 
-       INIT_WORK(&radio->radio_work, si470x_i2c_interrupt_work);
        radio->users = 0;
        radio->client = client;
        mutex_init(&radio->lock);
@@ -441,7 +437,11 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
        radio->rd_index = 0;
        init_waitqueue_head(&radio->read_queue);
 
-       retval = request_irq(client->irq, si470x_i2c_interrupt,
+       /* mark Seek/Tune Complete Interrupt enabled */
+       radio->stci_enabled = true;
+       init_completion(&radio->completion);
+
+       retval = request_threaded_irq(client->irq, NULL, si470x_i2c_interrupt,
                        IRQF_TRIGGER_FALLING, DRIVER_NAME, radio);
        if (retval) {
                dev_err(&client->dev, "Failed to register interrupt\n");
@@ -479,7 +479,6 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client)
        struct si470x_device *radio = i2c_get_clientdata(client);
 
        free_irq(client->irq, radio);
-       cancel_work_sync(&radio->radio_work);
        video_unregister_device(radio->videodev);
        kfree(radio);
 
@@ -491,8 +490,9 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client)
 /*
  * si470x_i2c_suspend - suspend the device
  */
-static int si470x_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+static int si470x_i2c_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct si470x_device *radio = i2c_get_clientdata(client);
 
        /* power down */
@@ -507,8 +507,9 @@ static int si470x_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
 /*
  * si470x_i2c_resume - resume the device
  */
-static int si470x_i2c_resume(struct i2c_client *client)
+static int si470x_i2c_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct si470x_device *radio = i2c_get_clientdata(client);
 
        /* power up : need 110ms */
@@ -519,9 +520,8 @@ static int si470x_i2c_resume(struct i2c_client *client)
 
        return 0;
 }
-#else
-#define si470x_i2c_suspend     NULL
-#define si470x_i2c_resume      NULL
+
+static SIMPLE_DEV_PM_OPS(si470x_i2c_pm, si470x_i2c_suspend, si470x_i2c_resume);
 #endif
 
 
@@ -532,11 +532,12 @@ static struct i2c_driver si470x_i2c_driver = {
        .driver = {
                .name           = "si470x",
                .owner          = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm             = &si470x_i2c_pm,
+#endif
        },
        .probe                  = si470x_i2c_probe,
        .remove                 = __devexit_p(si470x_i2c_remove),
-       .suspend                = si470x_i2c_suspend,
-       .resume                 = si470x_i2c_resume,
        .id_table               = si470x_i2c_id,
 };