summaryrefslogtreecommitdiffstats
path: root/drivers/media/rc/fintek-cir.h
blob: ac34a774d018343d16a48c9e3ea1e56b91b0cca6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/*
 * Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR
 *
 * Copyright (C) 2011 Jarod Wilson <jarod@redhat.com>
 *
 * Special thanks to Fintek for providing hardware and spec sheets.
 * This driver is based upon the nuvoton, ite and ene drivers for
 * similar hardware.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */

#include <linux/spinlock.h>
#include <linux/ioctl.h>

/* platform driver name to register */
#define FINTEK_DRIVER_NAME	"fintek-cir"
#define FINTEK_DESCRIPTION	"Fintek LPC SuperIO Consumer IR Transceiver"
#define VENDOR_ID_FINTEK	0x1934


/* debugging module parameter */
static int debug;

#define fit_pr(level, text, ...) \
	printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__)

#define fit_dbg(text, ...) \
	if (debug) \
		printk(KERN_DEBUG \
			KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)

#define fit_dbg_verbose(text, ...) \
	if (debug > 1) \
		printk(KERN_DEBUG \
			KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)

#define fit_dbg_wake(text, ...) \
	if (debug > 2) \
		printk(KERN_DEBUG \
			KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)


#define TX_BUF_LEN 256
#define RX_BUF_LEN 32

struct fintek_dev {
	struct pnp_dev *pdev;
	struct rc_dev *rdev;

	spinlock_t fintek_lock;

	/* for rx */
	u8 buf[RX_BUF_LEN];
	unsigned int pkts;

	struct {
		spinlock_t lock;
		u8 buf[TX_BUF_LEN];
		unsigned int buf_count;
		unsigned int cur_buf_num;
		wait_queue_head_t queue;
	} tx;

	/* Config register index/data port pair */
	u32 cr_ip;
	u32 cr_dp;

	/* hardware I/O settings */
	unsigned long cir_addr;
	int cir_irq;
	int cir_port_len;

	/* hardware id */
	u8 chip_major;
	u8 chip_minor;
	u16 chip_vendor;
	u8 logical_dev_cir;

	/* hardware features */
	bool hw_learning_capable;
	bool hw_tx_capable;

	/* rx settings */
	bool learning_enabled;
	bool carrier_detect_enabled;

	enum {
		CMD_HEADER = 0,
		SUBCMD,
		CMD_DATA,
		PARSE_IRDATA,
	} parser_state;

	u8 cmd, rem;

	/* carrier period = 1 / frequency */
	u32 carrier;
};

/* buffer packet constants, largely identical to mceusb.c */
#define BUF_PULSE_BIT		0x80
#define BUF_LEN_MASK		0x1f
#define BUF_SAMPLE_MASK		0x7f

#define BUF_COMMAND_HEADER	0x9f
#define BUF_COMMAND_MASK	0xe0
#define BUF_COMMAND_NULL	0x00
#define BUF_HW_CMD_HEADER	0xff
#define BUF_CMD_G_REVISION	0x0b
#define BUF_CMD_S_CARRIER	0x06
#define BUF_CMD_S_TIMEOUT	0x0c
#define BUF_CMD_SIG_END		0x01
#define BUF_CMD_S_TXMASK	0x08
#define BUF_CMD_S_RXSENSOR	0x14
#define BUF_RSP_PULSE_COUNT	0x15

#define CIR_SAMPLE_PERIOD	50

/*
 * Configuration Register:
 *  Index Port
 *  Data Port
 */
#define CR_INDEX_PORT		0x2e
#define CR_DATA_PORT		0x2f

/* Possible alternate values, depends on how the chip is wired */
#define CR_INDEX_PORT2		0x4e
#define CR_DATA_PORT2		0x4f

/*
 * GCR_CONFIG_PORT_SEL bit 4 specifies which Index Port value is
 * active. 1 = 0x4e, 0 = 0x2e
 */
#define PORT_SEL_PORT_4E_EN	0x10

/* Extended Function Mode enable/disable magic values */
#define CONFIG_REG_ENABLE	0x87
#define CONFIG_REG_DISABLE	0xaa

/* Chip IDs found in CR_CHIP_ID_{HI,LO} */
#define CHIP_ID_HIGH_F71809U	0x04
#define CHIP_ID_LOW_F71809U	0x08

/*
 * Global control regs we need to care about:
 *      Global Control                  def.
 *      Register name           addr    val. */
#define GCR_SOFTWARE_RESET	0x02 /* 0x00 */
#define GCR_LOGICAL_DEV_NO	0x07 /* 0x00 */
#define GCR_CHIP_ID_HI		0x20 /* 0x04 */
#define GCR_CHIP_ID_LO		0x21 /* 0x08 */
#define GCR_VENDOR_ID_HI	0x23 /* 0x19 */
#define GCR_VENDOR_ID_LO	0x24 /* 0x34 */
#define GCR_CONFIG_PORT_SEL	0x25 /* 0x01 */
#define GCR_KBMOUSE_WAKEUP	0x27

#define LOGICAL_DEV_DISABLE	0x00
#define LOGICAL_DEV_ENABLE	0x01

/* Logical device number of the CIR function */
#define LOGICAL_DEV_CIR_REV1	0x05
#define LOGICAL_DEV_CIR_REV2	0x08

/* CIR Logical Device (LDN 0x08) config registers */
#define CIR_CR_COMMAND_INDEX	0x04
#define CIR_CR_IRCS		0x05 /* Before host writes command to IR, host
					must set to 1. When host finshes write
					command to IR, host must clear to 0. */
#define CIR_CR_COMMAND_DATA	0x06 /* Host read or write comand data */
#define CIR_CR_CLASS		0x07 /* 0xff = rx-only, 0x66 = rx + 2 tx,
					0x33 = rx + 1 tx */
#define CIR_CR_DEV_EN		0x30 /* bit0 = 1 enables CIR */
#define CIR_CR_BASE_ADDR_HI	0x60 /* MSB of CIR IO base addr */
#define CIR_CR_BASE_ADDR_LO	0x61 /* LSB of CIR IO base addr */
#define CIR_CR_IRQ_SEL		0x70 /* bits3-0 store CIR IRQ */
#define CIR_CR_PSOUT_STATUS	0xf1
#define CIR_CR_WAKE_KEY3_ADDR	0xf8
#define CIR_CR_WAKE_KEY3_CODE	0xf9
#define CIR_CR_WAKE_KEY3_DC	0xfa
#define CIR_CR_WAKE_CONTROL	0xfb
#define CIR_CR_WAKE_KEY12_ADDR	0xfc
#define CIR_CR_WAKE_KEY4_ADDR	0xfd
#define CIR_CR_WAKE_KEY5_ADDR	0xfe

#define CLASS_RX_ONLY		0xff
#define CLASS_RX_2TX		0x66
#define CLASS_RX_1TX		0x33

/* CIR device registers */
#define CIR_STATUS		0x00
#define CIR_RX_DATA		0x01
#define CIR_TX_CONTROL		0x02
#define CIR_TX_DATA		0x03
#define CIR_CONTROL		0x04

/* Bits to enable CIR wake */
#define LOGICAL_DEV_ACPI	0x01
#define LDEV_ACPI_WAKE_EN_REG	0xe8
#define ACPI_WAKE_EN_CIR_BIT	0x04

#define LDEV_ACPI_PME_EN_REG	0xf0
#define LDEV_ACPI_PME_CLR_REG	0xf1
#define ACPI_PME_CIR_BIT	0x02

#define LDEV_ACPI_STATE_REG	0xf4
#define ACPI_STATE_CIR_BIT	0x20

/*
 * CIR status register (0x00):
 *   7 - CIR_IRQ_EN (1 = enable CIR IRQ, 0 = disable)
 *   3 - TX_FINISH (1 when TX finished, write 1 to clear)
 *   2 - TX_UNDERRUN (1 on TX underrun, write 1 to clear)
 *   1 - RX_TIMEOUT (1 on RX timeout, write 1 to clear)
 *   0 - RX_RECEIVE (1 on RX receive, write 1 to clear)
 */
#define CIR_STATUS_IRQ_EN	0x80
#define CIR_STATUS_TX_FINISH	0x08
#define CIR_STATUS_TX_UNDERRUN	0x04
#define CIR_STATUS_RX_TIMEOUT	0x02
#define CIR_STATUS_RX_RECEIVE	0x01
#define CIR_STATUS_IRQ_MASK	0x0f

/*
 * CIR TX control register (0x02):
 *   7 - TX_START (1 to indicate TX start, auto-cleared when done)
 *   6 - TX_END (1 to indicate TX data written to TX fifo)
 */
#define CIR_TX_CONTROL_TX_START	0x80
#define CIR_TX_CONTROL_TX_END	0x40

OpenPOWER on IntegriCloud