[media] media: rc: nuvoton-cir: add support for the NCT6779D
[deliverable/linux.git] / drivers / media / rc / nuvoton-cir.c
index 85af7a8691677a9b3965f469f37bc49b741de6b7..ff874fcae7d6492f99f98ec56c8eed2afd2d1423 100644 (file)
 
 #include "nuvoton-cir.h"
 
+static const struct nvt_chip nvt_chips[] = {
+       { "w83667hg", NVT_W83667HG },
+       { "NCT6775F", NVT_6775F },
+       { "NCT6776F", NVT_6776F },
+       { "NCT6779D", NVT_6779D },
+};
+
+static inline bool is_w83667hg(struct nvt_dev *nvt)
+{
+       return nvt->chip_ver == NVT_W83667HG;
+}
+
 /* write val to config reg */
 static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg)
 {
@@ -224,74 +236,59 @@ static void cir_wake_dump_regs(struct nvt_dev *nvt)
        pr_cont("\n");
 }
 
+static inline const char *nvt_find_chip(struct nvt_dev *nvt, int id)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(nvt_chips); i++)
+               if ((id & SIO_ID_MASK) == nvt_chips[i].chip_ver) {
+                       nvt->chip_ver = nvt_chips[i].chip_ver;
+                       return nvt_chips[i].name;
+               }
+
+       return NULL;
+}
+
+
 /* detect hardware features */
-static int nvt_hw_detect(struct nvt_dev *nvt)
+static void nvt_hw_detect(struct nvt_dev *nvt)
 {
-       unsigned long flags;
-       u8 chip_major, chip_minor;
-       char chip_id[12];
-       bool chip_unknown = false;
+       const char *chip_name;
+       int chip_id;
 
        nvt_efm_enable(nvt);
 
        /* Check if we're wired for the alternate EFER setup */
-       chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
-       if (chip_major == 0xff) {
+       nvt->chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
+       if (nvt->chip_major == 0xff) {
                nvt->cr_efir = CR_EFIR2;
                nvt->cr_efdr = CR_EFDR2;
                nvt_efm_enable(nvt);
-               chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
+               nvt->chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
        }
 
-       chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
-
-       /* these are the known working chip revisions... */
-       switch (chip_major) {
-       case CHIP_ID_HIGH_667:
-               strcpy(chip_id, "w83667hg\0");
-               if (chip_minor != CHIP_ID_LOW_667)
-                       chip_unknown = true;
-               break;
-       case CHIP_ID_HIGH_677B:
-               strcpy(chip_id, "w83677hg\0");
-               if (chip_minor != CHIP_ID_LOW_677B2 &&
-                   chip_minor != CHIP_ID_LOW_677B3)
-                       chip_unknown = true;
-               break;
-       case CHIP_ID_HIGH_677C:
-               strcpy(chip_id, "w83677hg-c\0");
-               if (chip_minor != CHIP_ID_LOW_677C)
-                       chip_unknown = true;
-               break;
-       default:
-               strcpy(chip_id, "w836x7hg\0");
-               chip_unknown = true;
-               break;
-       }
+       nvt->chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
+
+       chip_id = nvt->chip_major << 8 | nvt->chip_minor;
+       chip_name = nvt_find_chip(nvt, chip_id);
 
        /* warn, but still let the driver load, if we don't know this chip */
-       if (chip_unknown)
-               nvt_pr(KERN_WARNING, "%s: unknown chip, id: 0x%02x 0x%02x, "
-                      "it may not work...", chip_id, chip_major, chip_minor);
+       if (!chip_name)
+               nvt_pr(KERN_WARNING,
+                      "unknown chip, id: 0x%02x 0x%02x, it may not work...",
+                      nvt->chip_major, nvt->chip_minor);
        else
-               nvt_dbg("%s: chip id: 0x%02x 0x%02x",
-                       chip_id, chip_major, chip_minor);
+               nvt_dbg("found %s or compatible: chip id: 0x%02x 0x%02x",
+                       chip_name, nvt->chip_major, nvt->chip_minor);
 
        nvt_efm_disable(nvt);
-
-       spin_lock_irqsave(&nvt->nvt_lock, flags);
-       nvt->chip_major = chip_major;
-       nvt->chip_minor = chip_minor;
-       spin_unlock_irqrestore(&nvt->nvt_lock, flags);
-
-       return 0;
 }
 
 static void nvt_cir_ldev_init(struct nvt_dev *nvt)
 {
        u8 val, psreg, psmask, psval;
 
-       if (nvt->chip_major == CHIP_ID_HIGH_667) {
+       if (is_w83667hg(nvt)) {
                psreg = CR_MULTIFUNC_PIN_SEL;
                psmask = MULTIFUNC_PIN_SEL_MASK;
                psval = MULTIFUNC_ENABLE_CIR | MULTIFUNC_ENABLE_CIRWB;
@@ -779,7 +776,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
        if (!status) {
                nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__);
                nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
-               return IRQ_RETVAL(IRQ_NONE);
+               return IRQ_NONE;
        }
 
        /* ack/clear all irq flags we've got */
@@ -790,7 +787,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
        iren = nvt_cir_reg_read(nvt, CIR_IREN);
        if (!iren) {
                nvt_dbg_verbose("%s exiting, CIR not enabled", __func__);
-               return IRQ_RETVAL(IRQ_NONE);
+               return IRQ_NONE;
        }
 
        if (debug)
@@ -853,7 +850,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
        }
 
        nvt_dbg_verbose("%s done", __func__);
-       return IRQ_RETVAL(IRQ_HANDLED);
+       return IRQ_HANDLED;
 }
 
 /* Interrupt service routine for CIR Wake */
@@ -867,7 +864,7 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
 
        status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS);
        if (!status)
-               return IRQ_RETVAL(IRQ_NONE);
+               return IRQ_NONE;
 
        if (status & CIR_WAKE_IRSTS_IR_PENDING)
                nvt_clear_cir_wake_fifo(nvt);
@@ -879,7 +876,7 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
        iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN);
        if (!iren) {
                nvt_dbg_wake("%s exiting, wake not enabled", __func__);
-               return IRQ_RETVAL(IRQ_HANDLED);
+               return IRQ_HANDLED;
        }
 
        if ((status & CIR_WAKE_IRSTS_PE) &&
@@ -896,7 +893,7 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
        }
 
        nvt_dbg_wake("%s done", __func__);
-       return IRQ_RETVAL(IRQ_HANDLED);
+       return IRQ_HANDLED;
 }
 
 static void nvt_enable_cir(struct nvt_dev *nvt)
@@ -974,7 +971,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
        struct rc_dev *rdev;
        int ret = -ENOMEM;
 
-       nvt = kzalloc(sizeof(struct nvt_dev), GFP_KERNEL);
+       nvt = devm_kzalloc(&pdev->dev, sizeof(struct nvt_dev), GFP_KERNEL);
        if (!nvt)
                return ret;
 
@@ -1026,9 +1023,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 
        init_waitqueue_head(&nvt->tx.queue);
 
-       ret = nvt_hw_detect(nvt);
-       if (ret)
-               goto exit_free_dev_rdev;
+       nvt_hw_detect(nvt);
 
        /* Initialize CIR & CIR Wake Logical Devices */
        nvt_efm_enable(nvt);
@@ -1074,21 +1069,22 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 
        ret = -EBUSY;
        /* now claim resources */
-       if (!request_region(nvt->cir_addr,
+       if (!devm_request_region(&pdev->dev, nvt->cir_addr,
                            CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
                goto exit_unregister_device;
 
-       if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED,
-                       NVT_DRIVER_NAME, (void *)nvt))
-               goto exit_release_cir_addr;
+       if (devm_request_irq(&pdev->dev, nvt->cir_irq, nvt_cir_isr,
+                            IRQF_SHARED, NVT_DRIVER_NAME, (void *)nvt))
+               goto exit_unregister_device;
 
-       if (!request_region(nvt->cir_wake_addr,
+       if (!devm_request_region(&pdev->dev, nvt->cir_wake_addr,
                            CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
-               goto exit_free_irq;
+               goto exit_unregister_device;
 
-       if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED,
-                       NVT_DRIVER_NAME, (void *)nvt))
-               goto exit_release_cir_wake_addr;
+       if (devm_request_irq(&pdev->dev, nvt->cir_wake_irq,
+                            nvt_cir_wake_isr, IRQF_SHARED,
+                            NVT_DRIVER_NAME, (void *)nvt))
+               goto exit_unregister_device;
 
        device_init_wakeup(&pdev->dev, true);
 
@@ -1100,18 +1096,11 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 
        return 0;
 
-exit_release_cir_wake_addr:
-       release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
-exit_free_irq:
-       free_irq(nvt->cir_irq, nvt);
-exit_release_cir_addr:
-       release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
 exit_unregister_device:
        rc_unregister_device(rdev);
        rdev = NULL;
 exit_free_dev_rdev:
        rc_free_device(rdev);
-       kfree(nvt);
 
        return ret;
 }
@@ -1129,15 +1118,7 @@ static void nvt_remove(struct pnp_dev *pdev)
        nvt_enable_wake(nvt);
        spin_unlock_irqrestore(&nvt->nvt_lock, flags);
 
-       /* free resources */
-       free_irq(nvt->cir_irq, nvt);
-       free_irq(nvt->cir_wake_irq, nvt);
-       release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
-       release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
-
        rc_unregister_device(nvt->rdev);
-
-       kfree(nvt);
 }
 
 static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state)
This page took 0.041215 seconds and 5 git commands to generate.