cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fintek-cir.c (17851B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR
      4 *
      5 * Copyright (C) 2011 Jarod Wilson <jarod@redhat.com>
      6 *
      7 * Special thanks to Fintek for providing hardware and spec sheets.
      8 * This driver is based upon the nuvoton, ite and ene drivers for
      9 * similar hardware.
     10 */
     11
     12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     13
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/pnp.h>
     17#include <linux/io.h>
     18#include <linux/interrupt.h>
     19#include <linux/sched.h>
     20#include <linux/slab.h>
     21#include <media/rc-core.h>
     22
     23#include "fintek-cir.h"
     24
     25/* write val to config reg */
     26static inline void fintek_cr_write(struct fintek_dev *fintek, u8 val, u8 reg)
     27{
     28	fit_dbg("%s: reg 0x%02x, val 0x%02x  (ip/dp: %02x/%02x)",
     29		__func__, reg, val, fintek->cr_ip, fintek->cr_dp);
     30	outb(reg, fintek->cr_ip);
     31	outb(val, fintek->cr_dp);
     32}
     33
     34/* read val from config reg */
     35static inline u8 fintek_cr_read(struct fintek_dev *fintek, u8 reg)
     36{
     37	u8 val;
     38
     39	outb(reg, fintek->cr_ip);
     40	val = inb(fintek->cr_dp);
     41
     42	fit_dbg("%s: reg 0x%02x, val 0x%02x  (ip/dp: %02x/%02x)",
     43		__func__, reg, val, fintek->cr_ip, fintek->cr_dp);
     44	return val;
     45}
     46
     47/* update config register bit without changing other bits */
     48static inline void fintek_set_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg)
     49{
     50	u8 tmp = fintek_cr_read(fintek, reg) | val;
     51	fintek_cr_write(fintek, tmp, reg);
     52}
     53
     54/* enter config mode */
     55static inline void fintek_config_mode_enable(struct fintek_dev *fintek)
     56{
     57	/* Enabling Config Mode explicitly requires writing 2x */
     58	outb(CONFIG_REG_ENABLE, fintek->cr_ip);
     59	outb(CONFIG_REG_ENABLE, fintek->cr_ip);
     60}
     61
     62/* exit config mode */
     63static inline void fintek_config_mode_disable(struct fintek_dev *fintek)
     64{
     65	outb(CONFIG_REG_DISABLE, fintek->cr_ip);
     66}
     67
     68/*
     69 * When you want to address a specific logical device, write its logical
     70 * device number to GCR_LOGICAL_DEV_NO
     71 */
     72static inline void fintek_select_logical_dev(struct fintek_dev *fintek, u8 ldev)
     73{
     74	fintek_cr_write(fintek, ldev, GCR_LOGICAL_DEV_NO);
     75}
     76
     77/* write val to cir config register */
     78static inline void fintek_cir_reg_write(struct fintek_dev *fintek, u8 val, u8 offset)
     79{
     80	outb(val, fintek->cir_addr + offset);
     81}
     82
     83/* read val from cir config register */
     84static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset)
     85{
     86	return inb(fintek->cir_addr + offset);
     87}
     88
     89/* dump current cir register contents */
     90static void cir_dump_regs(struct fintek_dev *fintek)
     91{
     92	fintek_config_mode_enable(fintek);
     93	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
     94
     95	pr_info("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME);
     96	pr_info(" * CR CIR BASE ADDR: 0x%x\n",
     97		(fintek_cr_read(fintek, CIR_CR_BASE_ADDR_HI) << 8) |
     98		fintek_cr_read(fintek, CIR_CR_BASE_ADDR_LO));
     99	pr_info(" * CR CIR IRQ NUM:   0x%x\n",
    100		fintek_cr_read(fintek, CIR_CR_IRQ_SEL));
    101
    102	fintek_config_mode_disable(fintek);
    103
    104	pr_info("%s: Dump CIR registers:\n", FINTEK_DRIVER_NAME);
    105	pr_info(" * STATUS:     0x%x\n",
    106		fintek_cir_reg_read(fintek, CIR_STATUS));
    107	pr_info(" * CONTROL:    0x%x\n",
    108		fintek_cir_reg_read(fintek, CIR_CONTROL));
    109	pr_info(" * RX_DATA:    0x%x\n",
    110		fintek_cir_reg_read(fintek, CIR_RX_DATA));
    111	pr_info(" * TX_CONTROL: 0x%x\n",
    112		fintek_cir_reg_read(fintek, CIR_TX_CONTROL));
    113	pr_info(" * TX_DATA:    0x%x\n",
    114		fintek_cir_reg_read(fintek, CIR_TX_DATA));
    115}
    116
    117/* detect hardware features */
    118static int fintek_hw_detect(struct fintek_dev *fintek)
    119{
    120	unsigned long flags;
    121	u8 chip_major, chip_minor;
    122	u8 vendor_major, vendor_minor;
    123	u8 portsel, ir_class;
    124	u16 vendor, chip;
    125
    126	fintek_config_mode_enable(fintek);
    127
    128	/* Check if we're using config port 0x4e or 0x2e */
    129	portsel = fintek_cr_read(fintek, GCR_CONFIG_PORT_SEL);
    130	if (portsel == 0xff) {
    131		fit_pr(KERN_INFO, "first portsel read was bunk, trying alt");
    132		fintek_config_mode_disable(fintek);
    133		fintek->cr_ip = CR_INDEX_PORT2;
    134		fintek->cr_dp = CR_DATA_PORT2;
    135		fintek_config_mode_enable(fintek);
    136		portsel = fintek_cr_read(fintek, GCR_CONFIG_PORT_SEL);
    137	}
    138	fit_dbg("portsel reg: 0x%02x", portsel);
    139
    140	ir_class = fintek_cir_reg_read(fintek, CIR_CR_CLASS);
    141	fit_dbg("ir_class reg: 0x%02x", ir_class);
    142
    143	switch (ir_class) {
    144	case CLASS_RX_2TX:
    145	case CLASS_RX_1TX:
    146		fintek->hw_tx_capable = true;
    147		break;
    148	case CLASS_RX_ONLY:
    149	default:
    150		fintek->hw_tx_capable = false;
    151		break;
    152	}
    153
    154	chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI);
    155	chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO);
    156	chip  = chip_major << 8 | chip_minor;
    157
    158	vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI);
    159	vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO);
    160	vendor = vendor_major << 8 | vendor_minor;
    161
    162	if (vendor != VENDOR_ID_FINTEK)
    163		fit_pr(KERN_WARNING, "Unknown vendor ID: 0x%04x", vendor);
    164	else
    165		fit_dbg("Read Fintek vendor ID from chip");
    166
    167	fintek_config_mode_disable(fintek);
    168
    169	spin_lock_irqsave(&fintek->fintek_lock, flags);
    170	fintek->chip_major  = chip_major;
    171	fintek->chip_minor  = chip_minor;
    172	fintek->chip_vendor = vendor;
    173
    174	/*
    175	 * Newer reviews of this chipset uses port 8 instead of 5
    176	 */
    177	if ((chip != 0x0408) && (chip != 0x0804))
    178		fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV2;
    179	else
    180		fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV1;
    181
    182	spin_unlock_irqrestore(&fintek->fintek_lock, flags);
    183
    184	return 0;
    185}
    186
    187static void fintek_cir_ldev_init(struct fintek_dev *fintek)
    188{
    189	/* Select CIR logical device and enable */
    190	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
    191	fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
    192
    193	/* Write allocated CIR address and IRQ information to hardware */
    194	fintek_cr_write(fintek, fintek->cir_addr >> 8, CIR_CR_BASE_ADDR_HI);
    195	fintek_cr_write(fintek, fintek->cir_addr & 0xff, CIR_CR_BASE_ADDR_LO);
    196
    197	fintek_cr_write(fintek, fintek->cir_irq, CIR_CR_IRQ_SEL);
    198
    199	fit_dbg("CIR initialized, base io address: 0x%lx, irq: %d (len: %d)",
    200		fintek->cir_addr, fintek->cir_irq, fintek->cir_port_len);
    201}
    202
    203/* enable CIR interrupts */
    204static void fintek_enable_cir_irq(struct fintek_dev *fintek)
    205{
    206	fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_EN, CIR_STATUS);
    207}
    208
    209static void fintek_cir_regs_init(struct fintek_dev *fintek)
    210{
    211	/* clear any and all stray interrupts */
    212	fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
    213
    214	/* and finally, enable interrupts */
    215	fintek_enable_cir_irq(fintek);
    216}
    217
    218static void fintek_enable_wake(struct fintek_dev *fintek)
    219{
    220	fintek_config_mode_enable(fintek);
    221	fintek_select_logical_dev(fintek, LOGICAL_DEV_ACPI);
    222
    223	/* Allow CIR PME's to wake system */
    224	fintek_set_reg_bit(fintek, ACPI_WAKE_EN_CIR_BIT, LDEV_ACPI_WAKE_EN_REG);
    225	/* Enable CIR PME's */
    226	fintek_set_reg_bit(fintek, ACPI_PME_CIR_BIT, LDEV_ACPI_PME_EN_REG);
    227	/* Clear CIR PME status register */
    228	fintek_set_reg_bit(fintek, ACPI_PME_CIR_BIT, LDEV_ACPI_PME_CLR_REG);
    229	/* Save state */
    230	fintek_set_reg_bit(fintek, ACPI_STATE_CIR_BIT, LDEV_ACPI_STATE_REG);
    231
    232	fintek_config_mode_disable(fintek);
    233}
    234
    235static int fintek_cmdsize(u8 cmd, u8 subcmd)
    236{
    237	int datasize = 0;
    238
    239	switch (cmd) {
    240	case BUF_COMMAND_NULL:
    241		if (subcmd == BUF_HW_CMD_HEADER)
    242			datasize = 1;
    243		break;
    244	case BUF_HW_CMD_HEADER:
    245		if (subcmd == BUF_CMD_G_REVISION)
    246			datasize = 2;
    247		break;
    248	case BUF_COMMAND_HEADER:
    249		switch (subcmd) {
    250		case BUF_CMD_S_CARRIER:
    251		case BUF_CMD_S_TIMEOUT:
    252		case BUF_RSP_PULSE_COUNT:
    253			datasize = 2;
    254			break;
    255		case BUF_CMD_SIG_END:
    256		case BUF_CMD_S_TXMASK:
    257		case BUF_CMD_S_RXSENSOR:
    258			datasize = 1;
    259			break;
    260		}
    261	}
    262
    263	return datasize;
    264}
    265
    266/* process ir data stored in driver buffer */
    267static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
    268{
    269	struct ir_raw_event rawir = {};
    270	u8 sample;
    271	bool event = false;
    272	int i;
    273
    274	for (i = 0; i < fintek->pkts; i++) {
    275		sample = fintek->buf[i];
    276		switch (fintek->parser_state) {
    277		case CMD_HEADER:
    278			fintek->cmd = sample;
    279			if ((fintek->cmd == BUF_COMMAND_HEADER) ||
    280			    ((fintek->cmd & BUF_COMMAND_MASK) !=
    281			     BUF_PULSE_BIT)) {
    282				fintek->parser_state = SUBCMD;
    283				continue;
    284			}
    285			fintek->rem = (fintek->cmd & BUF_LEN_MASK);
    286			fit_dbg("%s: rem: 0x%02x", __func__, fintek->rem);
    287			if (fintek->rem)
    288				fintek->parser_state = PARSE_IRDATA;
    289			else
    290				ir_raw_event_overflow(fintek->rdev);
    291			break;
    292		case SUBCMD:
    293			fintek->rem = fintek_cmdsize(fintek->cmd, sample);
    294			fintek->parser_state = CMD_DATA;
    295			break;
    296		case CMD_DATA:
    297			fintek->rem--;
    298			break;
    299		case PARSE_IRDATA:
    300			fintek->rem--;
    301			rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
    302			rawir.duration = (sample & BUF_SAMPLE_MASK)
    303					  * CIR_SAMPLE_PERIOD;
    304
    305			fit_dbg("Storing %s with duration %d",
    306				rawir.pulse ? "pulse" : "space",
    307				rawir.duration);
    308			if (ir_raw_event_store_with_filter(fintek->rdev,
    309									&rawir))
    310				event = true;
    311			break;
    312		}
    313
    314		if ((fintek->parser_state != CMD_HEADER) && !fintek->rem)
    315			fintek->parser_state = CMD_HEADER;
    316	}
    317
    318	fintek->pkts = 0;
    319
    320	if (event) {
    321		fit_dbg("Calling ir_raw_event_handle");
    322		ir_raw_event_handle(fintek->rdev);
    323	}
    324}
    325
    326/* copy data from hardware rx register into driver buffer */
    327static void fintek_get_rx_ir_data(struct fintek_dev *fintek, u8 rx_irqs)
    328{
    329	unsigned long flags;
    330	u8 sample, status;
    331
    332	spin_lock_irqsave(&fintek->fintek_lock, flags);
    333
    334	/*
    335	 * We must read data from CIR_RX_DATA until the hardware IR buffer
    336	 * is empty and clears the RX_TIMEOUT and/or RX_RECEIVE flags in
    337	 * the CIR_STATUS register
    338	 */
    339	do {
    340		sample = fintek_cir_reg_read(fintek, CIR_RX_DATA);
    341		fit_dbg("%s: sample: 0x%02x", __func__, sample);
    342
    343		fintek->buf[fintek->pkts] = sample;
    344		fintek->pkts++;
    345
    346		status = fintek_cir_reg_read(fintek, CIR_STATUS);
    347		if (!(status & CIR_STATUS_IRQ_EN))
    348			break;
    349	} while (status & rx_irqs);
    350
    351	fintek_process_rx_ir_data(fintek);
    352
    353	spin_unlock_irqrestore(&fintek->fintek_lock, flags);
    354}
    355
    356static void fintek_cir_log_irqs(u8 status)
    357{
    358	fit_pr(KERN_INFO, "IRQ 0x%02x:%s%s%s%s%s", status,
    359		status & CIR_STATUS_IRQ_EN	? " IRQEN"	: "",
    360		status & CIR_STATUS_TX_FINISH	? " TXF"	: "",
    361		status & CIR_STATUS_TX_UNDERRUN	? " TXU"	: "",
    362		status & CIR_STATUS_RX_TIMEOUT	? " RXTO"	: "",
    363		status & CIR_STATUS_RX_RECEIVE	? " RXOK"	: "");
    364}
    365
    366/* interrupt service routine for incoming and outgoing CIR data */
    367static irqreturn_t fintek_cir_isr(int irq, void *data)
    368{
    369	struct fintek_dev *fintek = data;
    370	u8 status, rx_irqs;
    371
    372	fit_dbg_verbose("%s firing", __func__);
    373
    374	fintek_config_mode_enable(fintek);
    375	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
    376	fintek_config_mode_disable(fintek);
    377
    378	/*
    379	 * Get IR Status register contents. Write 1 to ack/clear
    380	 *
    381	 * bit: reg name    - description
    382	 *   3: TX_FINISH   - TX is finished
    383	 *   2: TX_UNDERRUN - TX underrun
    384	 *   1: RX_TIMEOUT  - RX data timeout
    385	 *   0: RX_RECEIVE  - RX data received
    386	 */
    387	status = fintek_cir_reg_read(fintek, CIR_STATUS);
    388	if (!(status & CIR_STATUS_IRQ_MASK) || status == 0xff) {
    389		fit_dbg_verbose("%s exiting, IRSTS 0x%02x", __func__, status);
    390		fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
    391		return IRQ_RETVAL(IRQ_NONE);
    392	}
    393
    394	if (debug)
    395		fintek_cir_log_irqs(status);
    396
    397	rx_irqs = status & (CIR_STATUS_RX_RECEIVE | CIR_STATUS_RX_TIMEOUT);
    398	if (rx_irqs)
    399		fintek_get_rx_ir_data(fintek, rx_irqs);
    400
    401	/* ack/clear all irq flags we've got */
    402	fintek_cir_reg_write(fintek, status, CIR_STATUS);
    403
    404	fit_dbg_verbose("%s done", __func__);
    405	return IRQ_RETVAL(IRQ_HANDLED);
    406}
    407
    408static void fintek_enable_cir(struct fintek_dev *fintek)
    409{
    410	/* set IRQ enabled */
    411	fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_EN, CIR_STATUS);
    412
    413	fintek_config_mode_enable(fintek);
    414
    415	/* enable the CIR logical device */
    416	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
    417	fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
    418
    419	fintek_config_mode_disable(fintek);
    420
    421	/* clear all pending interrupts */
    422	fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
    423
    424	/* enable interrupts */
    425	fintek_enable_cir_irq(fintek);
    426}
    427
    428static void fintek_disable_cir(struct fintek_dev *fintek)
    429{
    430	fintek_config_mode_enable(fintek);
    431
    432	/* disable the CIR logical device */
    433	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
    434	fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
    435
    436	fintek_config_mode_disable(fintek);
    437}
    438
    439static int fintek_open(struct rc_dev *dev)
    440{
    441	struct fintek_dev *fintek = dev->priv;
    442	unsigned long flags;
    443
    444	spin_lock_irqsave(&fintek->fintek_lock, flags);
    445	fintek_enable_cir(fintek);
    446	spin_unlock_irqrestore(&fintek->fintek_lock, flags);
    447
    448	return 0;
    449}
    450
    451static void fintek_close(struct rc_dev *dev)
    452{
    453	struct fintek_dev *fintek = dev->priv;
    454	unsigned long flags;
    455
    456	spin_lock_irqsave(&fintek->fintek_lock, flags);
    457	fintek_disable_cir(fintek);
    458	spin_unlock_irqrestore(&fintek->fintek_lock, flags);
    459}
    460
    461/* Allocate memory, probe hardware, and initialize everything */
    462static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
    463{
    464	struct fintek_dev *fintek;
    465	struct rc_dev *rdev;
    466	int ret = -ENOMEM;
    467
    468	fintek = kzalloc(sizeof(struct fintek_dev), GFP_KERNEL);
    469	if (!fintek)
    470		return ret;
    471
    472	/* input device for IR remote (and tx) */
    473	rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
    474	if (!rdev)
    475		goto exit_free_dev_rdev;
    476
    477	ret = -ENODEV;
    478	/* validate pnp resources */
    479	if (!pnp_port_valid(pdev, 0)) {
    480		dev_err(&pdev->dev, "IR PNP Port not valid!\n");
    481		goto exit_free_dev_rdev;
    482	}
    483
    484	if (!pnp_irq_valid(pdev, 0)) {
    485		dev_err(&pdev->dev, "IR PNP IRQ not valid!\n");
    486		goto exit_free_dev_rdev;
    487	}
    488
    489	fintek->cir_addr = pnp_port_start(pdev, 0);
    490	fintek->cir_irq  = pnp_irq(pdev, 0);
    491	fintek->cir_port_len = pnp_port_len(pdev, 0);
    492
    493	fintek->cr_ip = CR_INDEX_PORT;
    494	fintek->cr_dp = CR_DATA_PORT;
    495
    496	spin_lock_init(&fintek->fintek_lock);
    497
    498	pnp_set_drvdata(pdev, fintek);
    499	fintek->pdev = pdev;
    500
    501	ret = fintek_hw_detect(fintek);
    502	if (ret)
    503		goto exit_free_dev_rdev;
    504
    505	/* Initialize CIR & CIR Wake Logical Devices */
    506	fintek_config_mode_enable(fintek);
    507	fintek_cir_ldev_init(fintek);
    508	fintek_config_mode_disable(fintek);
    509
    510	/* Initialize CIR & CIR Wake Config Registers */
    511	fintek_cir_regs_init(fintek);
    512
    513	/* Set up the rc device */
    514	rdev->priv = fintek;
    515	rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
    516	rdev->open = fintek_open;
    517	rdev->close = fintek_close;
    518	rdev->device_name = FINTEK_DESCRIPTION;
    519	rdev->input_phys = "fintek/cir0";
    520	rdev->input_id.bustype = BUS_HOST;
    521	rdev->input_id.vendor = VENDOR_ID_FINTEK;
    522	rdev->input_id.product = fintek->chip_major;
    523	rdev->input_id.version = fintek->chip_minor;
    524	rdev->dev.parent = &pdev->dev;
    525	rdev->driver_name = FINTEK_DRIVER_NAME;
    526	rdev->map_name = RC_MAP_RC6_MCE;
    527	rdev->timeout = 1000;
    528	/* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
    529	rdev->rx_resolution = CIR_SAMPLE_PERIOD;
    530
    531	fintek->rdev = rdev;
    532
    533	ret = -EBUSY;
    534	/* now claim resources */
    535	if (!request_region(fintek->cir_addr,
    536			    fintek->cir_port_len, FINTEK_DRIVER_NAME))
    537		goto exit_free_dev_rdev;
    538
    539	if (request_irq(fintek->cir_irq, fintek_cir_isr, IRQF_SHARED,
    540			FINTEK_DRIVER_NAME, (void *)fintek))
    541		goto exit_free_cir_addr;
    542
    543	ret = rc_register_device(rdev);
    544	if (ret)
    545		goto exit_free_irq;
    546
    547	device_init_wakeup(&pdev->dev, true);
    548
    549	fit_pr(KERN_NOTICE, "driver has been successfully loaded\n");
    550	if (debug)
    551		cir_dump_regs(fintek);
    552
    553	return 0;
    554
    555exit_free_irq:
    556	free_irq(fintek->cir_irq, fintek);
    557exit_free_cir_addr:
    558	release_region(fintek->cir_addr, fintek->cir_port_len);
    559exit_free_dev_rdev:
    560	rc_free_device(rdev);
    561	kfree(fintek);
    562
    563	return ret;
    564}
    565
    566static void fintek_remove(struct pnp_dev *pdev)
    567{
    568	struct fintek_dev *fintek = pnp_get_drvdata(pdev);
    569	unsigned long flags;
    570
    571	spin_lock_irqsave(&fintek->fintek_lock, flags);
    572	/* disable CIR */
    573	fintek_disable_cir(fintek);
    574	fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
    575	/* enable CIR Wake (for IR power-on) */
    576	fintek_enable_wake(fintek);
    577	spin_unlock_irqrestore(&fintek->fintek_lock, flags);
    578
    579	/* free resources */
    580	free_irq(fintek->cir_irq, fintek);
    581	release_region(fintek->cir_addr, fintek->cir_port_len);
    582
    583	rc_unregister_device(fintek->rdev);
    584
    585	kfree(fintek);
    586}
    587
    588static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state)
    589{
    590	struct fintek_dev *fintek = pnp_get_drvdata(pdev);
    591	unsigned long flags;
    592
    593	fit_dbg("%s called", __func__);
    594
    595	spin_lock_irqsave(&fintek->fintek_lock, flags);
    596
    597	/* disable all CIR interrupts */
    598	fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
    599
    600	spin_unlock_irqrestore(&fintek->fintek_lock, flags);
    601
    602	fintek_config_mode_enable(fintek);
    603
    604	/* disable cir logical dev */
    605	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
    606	fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
    607
    608	fintek_config_mode_disable(fintek);
    609
    610	/* make sure wake is enabled */
    611	fintek_enable_wake(fintek);
    612
    613	return 0;
    614}
    615
    616static int fintek_resume(struct pnp_dev *pdev)
    617{
    618	struct fintek_dev *fintek = pnp_get_drvdata(pdev);
    619
    620	fit_dbg("%s called", __func__);
    621
    622	/* open interrupt */
    623	fintek_enable_cir_irq(fintek);
    624
    625	/* Enable CIR logical device */
    626	fintek_config_mode_enable(fintek);
    627	fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
    628	fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
    629
    630	fintek_config_mode_disable(fintek);
    631
    632	fintek_cir_regs_init(fintek);
    633
    634	return 0;
    635}
    636
    637static void fintek_shutdown(struct pnp_dev *pdev)
    638{
    639	struct fintek_dev *fintek = pnp_get_drvdata(pdev);
    640	fintek_enable_wake(fintek);
    641}
    642
    643static const struct pnp_device_id fintek_ids[] = {
    644	{ "FIT0002", 0 },   /* CIR */
    645	{ "", 0 },
    646};
    647
    648static struct pnp_driver fintek_driver = {
    649	.name		= FINTEK_DRIVER_NAME,
    650	.id_table	= fintek_ids,
    651	.flags		= PNP_DRIVER_RES_DO_NOT_CHANGE,
    652	.probe		= fintek_probe,
    653	.remove		= fintek_remove,
    654	.suspend	= fintek_suspend,
    655	.resume		= fintek_resume,
    656	.shutdown	= fintek_shutdown,
    657};
    658
    659module_param(debug, int, S_IRUGO | S_IWUSR);
    660MODULE_PARM_DESC(debug, "Enable debugging output");
    661
    662MODULE_DEVICE_TABLE(pnp, fintek_ids);
    663MODULE_DESCRIPTION(FINTEK_DESCRIPTION " driver");
    664
    665MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
    666MODULE_LICENSE("GPL");
    667
    668module_pnp_driver(fintek_driver);