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