diff options
Diffstat (limited to 'drivers/media/rc/nuvoton-cir.c')
-rw-r--r-- | drivers/media/rc/nuvoton-cir.c | 358 |
1 files changed, 247 insertions, 111 deletions
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 18adf580f502..99b303b702ac 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -39,6 +39,8 @@ #include "nuvoton-cir.h" +static void nvt_clear_cir_wake_fifo(struct nvt_dev *nvt); + static const struct nvt_chip nvt_chips[] = { { "w83667hg", NVT_W83667HG }, { "NCT6775F", NVT_6775F }, @@ -80,17 +82,24 @@ static inline void nvt_clear_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg) } /* enter extended function mode */ -static inline void nvt_efm_enable(struct nvt_dev *nvt) +static inline int nvt_efm_enable(struct nvt_dev *nvt) { + if (!request_muxed_region(nvt->cr_efir, 2, NVT_DRIVER_NAME)) + return -EBUSY; + /* Enabling Extended Function Mode explicitly requires writing 2x */ outb(EFER_EFM_ENABLE, nvt->cr_efir); outb(EFER_EFM_ENABLE, nvt->cr_efir); + + return 0; } /* exit extended function mode */ static inline void nvt_efm_disable(struct nvt_dev *nvt) { outb(EFER_EFM_DISABLE, nvt->cr_efir); + + release_region(nvt->cr_efir, 2); } /* @@ -100,8 +109,25 @@ static inline void nvt_efm_disable(struct nvt_dev *nvt) */ static inline void nvt_select_logical_dev(struct nvt_dev *nvt, u8 ldev) { - outb(CR_LOGICAL_DEV_SEL, nvt->cr_efir); - outb(ldev, nvt->cr_efdr); + nvt_cr_write(nvt, ldev, CR_LOGICAL_DEV_SEL); +} + +/* select and enable logical device with setting EFM mode*/ +static inline void nvt_enable_logical_dev(struct nvt_dev *nvt, u8 ldev) +{ + nvt_efm_enable(nvt); + nvt_select_logical_dev(nvt, ldev); + nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); + nvt_efm_disable(nvt); +} + +/* select and disable logical device with setting EFM mode*/ +static inline void nvt_disable_logical_dev(struct nvt_dev *nvt, u8 ldev) +{ + nvt_efm_enable(nvt); + nvt_select_logical_dev(nvt, ldev); + nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN); + nvt_efm_disable(nvt); } /* write val to cir config register */ @@ -137,6 +163,120 @@ static u8 nvt_cir_wake_reg_read(struct nvt_dev *nvt, u8 offset) return val; } +/* don't override io address if one is set already */ +static void nvt_set_ioaddr(struct nvt_dev *nvt, unsigned long *ioaddr) +{ + unsigned long old_addr; + + old_addr = nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8; + old_addr |= nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO); + + if (old_addr) + *ioaddr = old_addr; + else { + nvt_cr_write(nvt, *ioaddr >> 8, CR_CIR_BASE_ADDR_HI); + nvt_cr_write(nvt, *ioaddr & 0xff, CR_CIR_BASE_ADDR_LO); + } +} + +static ssize_t wakeup_data_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rc_dev *rc_dev = to_rc_dev(dev); + struct nvt_dev *nvt = rc_dev->priv; + int fifo_len, duration; + unsigned long flags; + ssize_t buf_len = 0; + int i; + + spin_lock_irqsave(&nvt->nvt_lock, flags); + + fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT); + fifo_len = min(fifo_len, WAKEUP_MAX_SIZE); + + /* go to first element to be read */ + while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) + nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY); + + for (i = 0; i < fifo_len; i++) { + duration = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY); + duration = (duration & BUF_LEN_MASK) * SAMPLE_PERIOD; + buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len, + "%d ", duration); + } + buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len, "\n"); + + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + + return buf_len; +} + +static ssize_t wakeup_data_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct rc_dev *rc_dev = to_rc_dev(dev); + struct nvt_dev *nvt = rc_dev->priv; + unsigned long flags; + u8 tolerance, config, wake_buf[WAKEUP_MAX_SIZE]; + char **argv; + int i, count; + unsigned int val; + ssize_t ret; + + argv = argv_split(GFP_KERNEL, buf, &count); + if (!argv) + return -ENOMEM; + if (!count || count > WAKEUP_MAX_SIZE) { + ret = -EINVAL; + goto out; + } + + for (i = 0; i < count; i++) { + ret = kstrtouint(argv[i], 10, &val); + if (ret) + goto out; + val = DIV_ROUND_CLOSEST(val, SAMPLE_PERIOD); + if (!val || val > 0x7f) { + ret = -EINVAL; + goto out; + } + wake_buf[i] = val; + /* sequence must start with a pulse */ + if (i % 2 == 0) + wake_buf[i] |= BUF_PULSE_BIT; + } + + /* hardcode the tolerance to 10% */ + tolerance = DIV_ROUND_UP(count, 10); + + spin_lock_irqsave(&nvt->nvt_lock, flags); + + nvt_clear_cir_wake_fifo(nvt); + nvt_cir_wake_reg_write(nvt, count, CIR_WAKE_FIFO_CMP_DEEP); + nvt_cir_wake_reg_write(nvt, tolerance, CIR_WAKE_FIFO_CMP_TOL); + + config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON); + + /* enable writes to wake fifo */ + nvt_cir_wake_reg_write(nvt, config | CIR_WAKE_IRCON_MODE1, + CIR_WAKE_IRCON); + + for (i = 0; i < count; i++) + nvt_cir_wake_reg_write(nvt, wake_buf[i], CIR_WAKE_WR_FIFO_DATA); + + nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON); + + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + + ret = len; +out: + argv_free(argv); + return ret; +} +static DEVICE_ATTR_RW(wakeup_data); + /* dump current cir register contents */ static void cir_dump_regs(struct nvt_dev *nvt) { @@ -251,7 +391,7 @@ static inline const char *nvt_find_chip(struct nvt_dev *nvt, int id) /* detect hardware features */ -static void nvt_hw_detect(struct nvt_dev *nvt) +static int nvt_hw_detect(struct nvt_dev *nvt) { const char *chip_name; int chip_id; @@ -266,10 +406,17 @@ static void nvt_hw_detect(struct nvt_dev *nvt) nvt_efm_enable(nvt); nvt->chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI); } - nvt->chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO); + nvt_efm_disable(nvt); + chip_id = nvt->chip_major << 8 | nvt->chip_minor; + if (chip_id == NVT_INVALID) { + dev_err(&nvt->pdev->dev, + "No device found on either EFM port\n"); + return -ENODEV; + } + chip_name = nvt_find_chip(nvt, chip_id); /* warn, but still let the driver load, if we don't know this chip */ @@ -282,7 +429,7 @@ static void nvt_hw_detect(struct nvt_dev *nvt) "found %s or compatible: chip id: 0x%02x 0x%02x", chip_name, nvt->chip_major, nvt->chip_minor); - nvt_efm_disable(nvt); + return 0; } static void nvt_cir_ldev_init(struct nvt_dev *nvt) @@ -305,12 +452,10 @@ static void nvt_cir_ldev_init(struct nvt_dev *nvt) val |= psval; nvt_cr_write(nvt, val, psreg); - /* Select CIR logical device and enable */ + /* Select CIR logical device */ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); - nvt_cr_write(nvt, nvt->cir_addr >> 8, CR_CIR_BASE_ADDR_HI); - nvt_cr_write(nvt, nvt->cir_addr & 0xff, CR_CIR_BASE_ADDR_LO); + nvt_set_ioaddr(nvt, &nvt->cir_addr); nvt_cr_write(nvt, nvt->cir_irq, CR_CIR_IRQ_RSRC); @@ -320,7 +465,7 @@ static void nvt_cir_ldev_init(struct nvt_dev *nvt) static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt) { - /* Select ACPI logical device, enable it and CIR Wake */ + /* Select ACPI logical device and anable it */ nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI); nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); @@ -330,12 +475,10 @@ static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt) /* enable pme interrupt of cir wakeup event */ nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2); - /* Select CIR Wake logical device and enable */ + /* Select CIR Wake logical device */ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); - nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); - nvt_cr_write(nvt, nvt->cir_wake_addr >> 8, CR_CIR_BASE_ADDR_HI); - nvt_cr_write(nvt, nvt->cir_wake_addr & 0xff, CR_CIR_BASE_ADDR_LO); + nvt_set_ioaddr(nvt, &nvt->cir_wake_addr); nvt_cr_write(nvt, nvt->cir_wake_irq, CR_CIR_IRQ_RSRC); @@ -355,11 +498,19 @@ static void nvt_clear_cir_fifo(struct nvt_dev *nvt) /* clear out the hardware's cir wake rx fifo */ static void nvt_clear_cir_wake_fifo(struct nvt_dev *nvt) { - u8 val; + u8 val, config; + + config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON); + + /* clearing wake fifo works in learning mode only */ + nvt_cir_wake_reg_write(nvt, config & ~CIR_WAKE_IRCON_MODE0, + CIR_WAKE_IRCON); val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON); nvt_cir_wake_reg_write(nvt, val | CIR_WAKE_FIFOCON_RXFIFOCLR, CIR_WAKE_FIFOCON); + + nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON); } /* clear out the hardware's cir tx fifo */ @@ -408,6 +559,9 @@ static void nvt_cir_regs_init(struct nvt_dev *nvt) /* and finally, enable interrupts */ nvt_set_cir_iren(nvt); + + /* enable the CIR logical device */ + nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR); } static void nvt_cir_wake_regs_init(struct nvt_dev *nvt) @@ -442,10 +596,15 @@ static void nvt_cir_wake_regs_init(struct nvt_dev *nvt) /* clear any and all stray interrupts */ nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS); + + /* enable the CIR WAKE logical device */ + nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); } static void nvt_enable_wake(struct nvt_dev *nvt) { + unsigned long flags; + nvt_efm_enable(nvt); nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI); @@ -457,12 +616,16 @@ static void nvt_enable_wake(struct nvt_dev *nvt) nvt_efm_disable(nvt); + spin_lock_irqsave(&nvt->nvt_lock, flags); + nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, CIR_WAKE_IRCON); nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS); nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN); + + spin_unlock_irqrestore(&nvt->nvt_lock, flags); } #if 0 /* Currently unused */ @@ -670,7 +833,6 @@ static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt) /* copy data from hardware rx fifo into driver buffer */ static void nvt_get_rx_ir_data(struct nvt_dev *nvt) { - unsigned long flags; u8 fifocount, val; unsigned int b_idx; bool overrun = false; @@ -689,8 +851,6 @@ static void nvt_get_rx_ir_data(struct nvt_dev *nvt) nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount); - spin_lock_irqsave(&nvt->nvt_lock, flags); - b_idx = nvt->pkts; /* This should never happen, but lets check anyway... */ @@ -712,8 +872,6 @@ static void nvt_get_rx_ir_data(struct nvt_dev *nvt) if (overrun) nvt_handle_rx_fifo_overrun(nvt); - - spin_unlock_irqrestore(&nvt->nvt_lock, flags); } static void nvt_cir_log_irqs(u8 status, u8 iren) @@ -736,16 +894,13 @@ static void nvt_cir_log_irqs(u8 status, u8 iren) static bool nvt_cir_tx_inactive(struct nvt_dev *nvt) { unsigned long flags; - bool tx_inactive; u8 tx_state; spin_lock_irqsave(&nvt->tx.lock, flags); tx_state = nvt->tx.tx_state; spin_unlock_irqrestore(&nvt->tx.lock, flags); - tx_inactive = (tx_state == ST_TX_NONE); - - return tx_inactive; + return tx_state == ST_TX_NONE; } /* interrupt service routine for incoming and outgoing CIR data */ @@ -757,9 +912,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) nvt_dbg_verbose("%s firing", __func__); - nvt_efm_enable(nvt); - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - nvt_efm_disable(nvt); + spin_lock_irqsave(&nvt->nvt_lock, flags); /* * Get IR Status register contents. Write 1 to ack/clear @@ -775,9 +928,14 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) * 0: CIR_IRSTS_GH - Min Length Detected */ status = nvt_cir_reg_read(nvt, CIR_IRSTS); - if (!status) { + iren = nvt_cir_reg_read(nvt, CIR_IREN); + + /* IRQ may be shared with CIR WAKE, therefore check for each + * status bit whether the related interrupt source is enabled + */ + if (!(status & iren)) { + spin_unlock_irqrestore(&nvt->nvt_lock, flags); nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__); - nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); return IRQ_NONE; } @@ -785,13 +943,6 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) nvt_cir_reg_write(nvt, status, CIR_IRSTS); nvt_cir_reg_write(nvt, 0, CIR_IRSTS); - /* Interrupt may be shared with CIR Wake, bail if CIR not enabled */ - iren = nvt_cir_reg_read(nvt, CIR_IREN); - if (!iren) { - nvt_dbg_verbose("%s exiting, CIR not enabled", __func__); - return IRQ_NONE; - } - nvt_cir_log_irqs(status, iren); if (status & CIR_IRSTS_RTR) { @@ -805,16 +956,14 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) if (nvt_cir_tx_inactive(nvt)) nvt_get_rx_ir_data(nvt); - spin_lock_irqsave(&nvt->nvt_lock, flags); - cur_state = nvt->study_state; - spin_unlock_irqrestore(&nvt->nvt_lock, flags); - if (cur_state == ST_STUDY_NONE) nvt_clear_cir_fifo(nvt); } + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + if (status & CIR_IRSTS_TE) nvt_clear_tx_fifo(nvt); @@ -863,9 +1012,18 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data) nvt_dbg_wake("%s firing", __func__); + spin_lock_irqsave(&nvt->nvt_lock, flags); + status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS); - if (!status) + iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN); + + /* IRQ may be shared with CIR, therefore check for each + * status bit whether the related interrupt source is enabled + */ + if (!(status & iren)) { + spin_unlock_irqrestore(&nvt->nvt_lock, flags); return IRQ_NONE; + } if (status & CIR_WAKE_IRSTS_IR_PENDING) nvt_clear_cir_wake_fifo(nvt); @@ -873,13 +1031,6 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data) nvt_cir_wake_reg_write(nvt, status, CIR_WAKE_IRSTS); nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IRSTS); - /* Interrupt may be shared with CIR, bail if Wake not enabled */ - iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN); - if (!iren) { - nvt_dbg_wake("%s exiting, wake not enabled", __func__); - return IRQ_HANDLED; - } - if ((status & CIR_WAKE_IRSTS_PE) && (nvt->wake_state == ST_WAKE_START)) { while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) { @@ -888,39 +1039,21 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data) } nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN); - spin_lock_irqsave(&nvt->nvt_lock, flags); nvt->wake_state = ST_WAKE_FINISH; - spin_unlock_irqrestore(&nvt->nvt_lock, flags); } + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + nvt_dbg_wake("%s done", __func__); return IRQ_HANDLED; } -static void nvt_enable_cir(struct nvt_dev *nvt) +static void nvt_disable_cir(struct nvt_dev *nvt) { - /* set function enable flags */ - nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN | - CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, - CIR_IRCON); - - nvt_efm_enable(nvt); - - /* enable the CIR logical device */ - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); - - nvt_efm_disable(nvt); - - /* clear all pending interrupts */ - nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); + unsigned long flags; - /* enable interrupts */ - nvt_set_cir_iren(nvt); -} + spin_lock_irqsave(&nvt->nvt_lock, flags); -static void nvt_disable_cir(struct nvt_dev *nvt) -{ /* disable CIR interrupts */ nvt_cir_reg_write(nvt, 0, CIR_IREN); @@ -934,13 +1067,10 @@ static void nvt_disable_cir(struct nvt_dev *nvt) nvt_clear_cir_fifo(nvt); nvt_clear_tx_fifo(nvt); - nvt_efm_enable(nvt); + spin_unlock_irqrestore(&nvt->nvt_lock, flags); /* disable the CIR logical device */ - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN); - - nvt_efm_disable(nvt); + nvt_disable_logical_dev(nvt, LOGICAL_DEV_CIR); } static int nvt_open(struct rc_dev *dev) @@ -949,20 +1079,31 @@ static int nvt_open(struct rc_dev *dev) unsigned long flags; spin_lock_irqsave(&nvt->nvt_lock, flags); - nvt_enable_cir(nvt); + + /* set function enable flags */ + nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN | + CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, + CIR_IRCON); + + /* clear all pending interrupts */ + nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); + + /* enable interrupts */ + nvt_set_cir_iren(nvt); + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + /* enable the CIR logical device */ + nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR); + return 0; } static void nvt_close(struct rc_dev *dev) { struct nvt_dev *nvt = dev->priv; - unsigned long flags; - spin_lock_irqsave(&nvt->nvt_lock, flags); nvt_disable_cir(nvt); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); } /* Allocate memory, probe hardware, and initialize everything */ @@ -1024,7 +1165,9 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) init_waitqueue_head(&nvt->tx.queue); - nvt_hw_detect(nvt); + ret = nvt_hw_detect(nvt); + if (ret) + goto exit_free_dev_rdev; /* Initialize CIR & CIR Wake Logical Devices */ nvt_efm_enable(nvt); @@ -1032,7 +1175,10 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) nvt_cir_wake_ldev_init(nvt); nvt_efm_disable(nvt); - /* Initialize CIR & CIR Wake Config Registers */ + /* + * Initialize CIR & CIR Wake Config Registers + * and enable logical devices + */ nvt_cir_regs_init(nvt); nvt_cir_wake_regs_init(nvt); @@ -1079,12 +1225,16 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) goto exit_unregister_device; if (!devm_request_region(&pdev->dev, nvt->cir_wake_addr, - CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) + CIR_IOREG_LENGTH, NVT_DRIVER_NAME "-wake")) goto exit_unregister_device; if (devm_request_irq(&pdev->dev, nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED, - NVT_DRIVER_NAME, (void *)nvt)) + NVT_DRIVER_NAME "-wake", (void *)nvt)) + goto exit_unregister_device; + + ret = device_create_file(&rdev->dev, &dev_attr_wakeup_data); + if (ret) goto exit_unregister_device; device_init_wakeup(&pdev->dev, true); @@ -1109,15 +1259,13 @@ exit_free_dev_rdev: static void nvt_remove(struct pnp_dev *pdev) { struct nvt_dev *nvt = pnp_get_drvdata(pdev); - unsigned long flags; - spin_lock_irqsave(&nvt->nvt_lock, flags); - /* disable CIR */ - nvt_cir_reg_write(nvt, 0, CIR_IREN); + device_remove_file(&nvt->rdev->dev, &dev_attr_wakeup_data); + nvt_disable_cir(nvt); + /* enable CIR Wake (for IR power-on) */ nvt_enable_wake(nvt); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); rc_unregister_device(nvt->rdev); } @@ -1129,26 +1277,23 @@ static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) nvt_dbg("%s called", __func__); - /* zero out misc state tracking */ - spin_lock_irqsave(&nvt->nvt_lock, flags); - nvt->study_state = ST_STUDY_NONE; - nvt->wake_state = ST_WAKE_NONE; - spin_unlock_irqrestore(&nvt->nvt_lock, flags); - spin_lock_irqsave(&nvt->tx.lock, flags); nvt->tx.tx_state = ST_TX_NONE; spin_unlock_irqrestore(&nvt->tx.lock, flags); + spin_lock_irqsave(&nvt->nvt_lock, flags); + + /* zero out misc state tracking */ + nvt->study_state = ST_STUDY_NONE; + nvt->wake_state = ST_WAKE_NONE; + /* disable all CIR interrupts */ nvt_cir_reg_write(nvt, 0, CIR_IREN); - nvt_efm_enable(nvt); + spin_unlock_irqrestore(&nvt->nvt_lock, flags); /* disable cir logical dev */ - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN); - - nvt_efm_disable(nvt); + nvt_disable_logical_dev(nvt, LOGICAL_DEV_CIR); /* make sure wake is enabled */ nvt_enable_wake(nvt); @@ -1162,16 +1307,6 @@ static int nvt_resume(struct pnp_dev *pdev) nvt_dbg("%s called", __func__); - /* open interrupt */ - nvt_set_cir_iren(nvt); - - /* Enable CIR logical device */ - nvt_efm_enable(nvt); - nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); - - nvt_efm_disable(nvt); - nvt_cir_regs_init(nvt); nvt_cir_wake_regs_init(nvt); @@ -1181,6 +1316,7 @@ static int nvt_resume(struct pnp_dev *pdev) static void nvt_shutdown(struct pnp_dev *pdev) { struct nvt_dev *nvt = pnp_get_drvdata(pdev); + nvt_enable_wake(nvt); } |