19bdc79eaSJarod Wilson /* 29bdc79eaSJarod Wilson * Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR 39bdc79eaSJarod Wilson * 49bdc79eaSJarod Wilson * Copyright (C) 2011 Jarod Wilson <jarod@redhat.com> 59bdc79eaSJarod Wilson * 69bdc79eaSJarod Wilson * Special thanks to Fintek for providing hardware and spec sheets. 79bdc79eaSJarod Wilson * This driver is based upon the nuvoton, ite and ene drivers for 89bdc79eaSJarod Wilson * similar hardware. 99bdc79eaSJarod Wilson * 109bdc79eaSJarod Wilson * This program is free software; you can redistribute it and/or 119bdc79eaSJarod Wilson * modify it under the terms of the GNU General Public License as 129bdc79eaSJarod Wilson * published by the Free Software Foundation; either version 2 of the 139bdc79eaSJarod Wilson * License, or (at your option) any later version. 149bdc79eaSJarod Wilson * 159bdc79eaSJarod Wilson * This program is distributed in the hope that it will be useful, but 169bdc79eaSJarod Wilson * WITHOUT ANY WARRANTY; without even the implied warranty of 179bdc79eaSJarod Wilson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 189bdc79eaSJarod Wilson * General Public License for more details. 199bdc79eaSJarod Wilson * 209bdc79eaSJarod Wilson * You should have received a copy of the GNU General Public License 219bdc79eaSJarod Wilson * along with this program; if not, write to the Free Software 229bdc79eaSJarod Wilson * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 239bdc79eaSJarod Wilson * USA 249bdc79eaSJarod Wilson */ 259bdc79eaSJarod Wilson 269bdc79eaSJarod Wilson #include <linux/spinlock.h> 279bdc79eaSJarod Wilson #include <linux/ioctl.h> 289bdc79eaSJarod Wilson 299bdc79eaSJarod Wilson /* platform driver name to register */ 309bdc79eaSJarod Wilson #define FINTEK_DRIVER_NAME "fintek-cir" 319bdc79eaSJarod Wilson #define FINTEK_DESCRIPTION "Fintek LPC SuperIO Consumer IR Transceiver" 329bdc79eaSJarod Wilson #define VENDOR_ID_FINTEK 0x1934 339bdc79eaSJarod Wilson 349bdc79eaSJarod Wilson 359bdc79eaSJarod Wilson /* debugging module parameter */ 369bdc79eaSJarod Wilson static int debug; 379bdc79eaSJarod Wilson 389bdc79eaSJarod Wilson #define fit_pr(level, text, ...) \ 399bdc79eaSJarod Wilson printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__) 409bdc79eaSJarod Wilson 419bdc79eaSJarod Wilson #define fit_dbg(text, ...) \ 429bdc79eaSJarod Wilson if (debug) \ 439bdc79eaSJarod Wilson printk(KERN_DEBUG \ 449bdc79eaSJarod Wilson KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) 459bdc79eaSJarod Wilson 469bdc79eaSJarod Wilson #define fit_dbg_verbose(text, ...) \ 479bdc79eaSJarod Wilson if (debug > 1) \ 489bdc79eaSJarod Wilson printk(KERN_DEBUG \ 499bdc79eaSJarod Wilson KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) 509bdc79eaSJarod Wilson 519bdc79eaSJarod Wilson #define fit_dbg_wake(text, ...) \ 529bdc79eaSJarod Wilson if (debug > 2) \ 539bdc79eaSJarod Wilson printk(KERN_DEBUG \ 549bdc79eaSJarod Wilson KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) 559bdc79eaSJarod Wilson 569bdc79eaSJarod Wilson 579bdc79eaSJarod Wilson #define TX_BUF_LEN 256 589bdc79eaSJarod Wilson #define RX_BUF_LEN 32 599bdc79eaSJarod Wilson 609bdc79eaSJarod Wilson struct fintek_dev { 619bdc79eaSJarod Wilson struct pnp_dev *pdev; 629bdc79eaSJarod Wilson struct rc_dev *rdev; 639bdc79eaSJarod Wilson 649bdc79eaSJarod Wilson spinlock_t fintek_lock; 659bdc79eaSJarod Wilson 669bdc79eaSJarod Wilson /* for rx */ 679bdc79eaSJarod Wilson u8 buf[RX_BUF_LEN]; 689bdc79eaSJarod Wilson unsigned int pkts; 699bdc79eaSJarod Wilson 709bdc79eaSJarod Wilson struct { 719bdc79eaSJarod Wilson spinlock_t lock; 729bdc79eaSJarod Wilson u8 buf[TX_BUF_LEN]; 739bdc79eaSJarod Wilson unsigned int buf_count; 749bdc79eaSJarod Wilson unsigned int cur_buf_num; 759bdc79eaSJarod Wilson wait_queue_head_t queue; 769bdc79eaSJarod Wilson } tx; 779bdc79eaSJarod Wilson 789bdc79eaSJarod Wilson /* Config register index/data port pair */ 79221cefa4SMauro Carvalho Chehab u32 cr_ip; 80221cefa4SMauro Carvalho Chehab u32 cr_dp; 819bdc79eaSJarod Wilson 829bdc79eaSJarod Wilson /* hardware I/O settings */ 839bdc79eaSJarod Wilson unsigned long cir_addr; 849bdc79eaSJarod Wilson int cir_irq; 859bdc79eaSJarod Wilson int cir_port_len; 869bdc79eaSJarod Wilson 879bdc79eaSJarod Wilson /* hardware id */ 889bdc79eaSJarod Wilson u8 chip_major; 899bdc79eaSJarod Wilson u8 chip_minor; 909bdc79eaSJarod Wilson u16 chip_vendor; 9183ec8225SMauro Carvalho Chehab u8 logical_dev_cir; 929bdc79eaSJarod Wilson 939bdc79eaSJarod Wilson /* hardware features */ 949bdc79eaSJarod Wilson bool hw_learning_capable; 959bdc79eaSJarod Wilson bool hw_tx_capable; 969bdc79eaSJarod Wilson 979bdc79eaSJarod Wilson /* rx settings */ 989bdc79eaSJarod Wilson bool learning_enabled; 999bdc79eaSJarod Wilson bool carrier_detect_enabled; 1009bdc79eaSJarod Wilson 1019bdc79eaSJarod Wilson enum { 1029bdc79eaSJarod Wilson CMD_HEADER = 0, 1039bdc79eaSJarod Wilson SUBCMD, 1049bdc79eaSJarod Wilson CMD_DATA, 1059bdc79eaSJarod Wilson PARSE_IRDATA, 1069bdc79eaSJarod Wilson } parser_state; 1079bdc79eaSJarod Wilson 1089bdc79eaSJarod Wilson u8 cmd, rem; 1099bdc79eaSJarod Wilson 1109bdc79eaSJarod Wilson /* carrier period = 1 / frequency */ 1119bdc79eaSJarod Wilson u32 carrier; 1129bdc79eaSJarod Wilson }; 1139bdc79eaSJarod Wilson 1149bdc79eaSJarod Wilson /* buffer packet constants, largely identical to mceusb.c */ 1159bdc79eaSJarod Wilson #define BUF_PULSE_BIT 0x80 1169bdc79eaSJarod Wilson #define BUF_LEN_MASK 0x1f 1179bdc79eaSJarod Wilson #define BUF_SAMPLE_MASK 0x7f 1189bdc79eaSJarod Wilson 1199bdc79eaSJarod Wilson #define BUF_COMMAND_HEADER 0x9f 1209bdc79eaSJarod Wilson #define BUF_COMMAND_MASK 0xe0 1219bdc79eaSJarod Wilson #define BUF_COMMAND_NULL 0x00 1229bdc79eaSJarod Wilson #define BUF_HW_CMD_HEADER 0xff 1239bdc79eaSJarod Wilson #define BUF_CMD_G_REVISION 0x0b 1249bdc79eaSJarod Wilson #define BUF_CMD_S_CARRIER 0x06 1259bdc79eaSJarod Wilson #define BUF_CMD_S_TIMEOUT 0x0c 1269bdc79eaSJarod Wilson #define BUF_CMD_SIG_END 0x01 1279bdc79eaSJarod Wilson #define BUF_CMD_S_TXMASK 0x08 1289bdc79eaSJarod Wilson #define BUF_CMD_S_RXSENSOR 0x14 1299bdc79eaSJarod Wilson #define BUF_RSP_PULSE_COUNT 0x15 1309bdc79eaSJarod Wilson 1319bdc79eaSJarod Wilson #define CIR_SAMPLE_PERIOD 50 1329bdc79eaSJarod Wilson 1339bdc79eaSJarod Wilson /* 1349bdc79eaSJarod Wilson * Configuration Register: 1359bdc79eaSJarod Wilson * Index Port 1369bdc79eaSJarod Wilson * Data Port 1379bdc79eaSJarod Wilson */ 1389bdc79eaSJarod Wilson #define CR_INDEX_PORT 0x2e 1399bdc79eaSJarod Wilson #define CR_DATA_PORT 0x2f 1409bdc79eaSJarod Wilson 1419bdc79eaSJarod Wilson /* Possible alternate values, depends on how the chip is wired */ 1429bdc79eaSJarod Wilson #define CR_INDEX_PORT2 0x4e 1439bdc79eaSJarod Wilson #define CR_DATA_PORT2 0x4f 1449bdc79eaSJarod Wilson 1459bdc79eaSJarod Wilson /* 1469bdc79eaSJarod Wilson * GCR_CONFIG_PORT_SEL bit 4 specifies which Index Port value is 1479bdc79eaSJarod Wilson * active. 1 = 0x4e, 0 = 0x2e 1489bdc79eaSJarod Wilson */ 1499bdc79eaSJarod Wilson #define PORT_SEL_PORT_4E_EN 0x10 1509bdc79eaSJarod Wilson 1519bdc79eaSJarod Wilson /* Extended Function Mode enable/disable magic values */ 1529bdc79eaSJarod Wilson #define CONFIG_REG_ENABLE 0x87 1539bdc79eaSJarod Wilson #define CONFIG_REG_DISABLE 0xaa 1549bdc79eaSJarod Wilson 1559bdc79eaSJarod Wilson /* Chip IDs found in CR_CHIP_ID_{HI,LO} */ 1569bdc79eaSJarod Wilson #define CHIP_ID_HIGH_F71809U 0x04 1579bdc79eaSJarod Wilson #define CHIP_ID_LOW_F71809U 0x08 1589bdc79eaSJarod Wilson 1599bdc79eaSJarod Wilson /* 1609bdc79eaSJarod Wilson * Global control regs we need to care about: 1619bdc79eaSJarod Wilson * Global Control def. 1629bdc79eaSJarod Wilson * Register name addr val. */ 1639bdc79eaSJarod Wilson #define GCR_SOFTWARE_RESET 0x02 /* 0x00 */ 1649bdc79eaSJarod Wilson #define GCR_LOGICAL_DEV_NO 0x07 /* 0x00 */ 1659bdc79eaSJarod Wilson #define GCR_CHIP_ID_HI 0x20 /* 0x04 */ 1669bdc79eaSJarod Wilson #define GCR_CHIP_ID_LO 0x21 /* 0x08 */ 1679bdc79eaSJarod Wilson #define GCR_VENDOR_ID_HI 0x23 /* 0x19 */ 1689bdc79eaSJarod Wilson #define GCR_VENDOR_ID_LO 0x24 /* 0x34 */ 1699bdc79eaSJarod Wilson #define GCR_CONFIG_PORT_SEL 0x25 /* 0x01 */ 1709bdc79eaSJarod Wilson #define GCR_KBMOUSE_WAKEUP 0x27 1719bdc79eaSJarod Wilson 1729bdc79eaSJarod Wilson #define LOGICAL_DEV_DISABLE 0x00 1739bdc79eaSJarod Wilson #define LOGICAL_DEV_ENABLE 0x01 1749bdc79eaSJarod Wilson 1759bdc79eaSJarod Wilson /* Logical device number of the CIR function */ 17683ec8225SMauro Carvalho Chehab #define LOGICAL_DEV_CIR_REV1 0x05 17783ec8225SMauro Carvalho Chehab #define LOGICAL_DEV_CIR_REV2 0x08 1789bdc79eaSJarod Wilson 1799bdc79eaSJarod Wilson /* CIR Logical Device (LDN 0x08) config registers */ 1809bdc79eaSJarod Wilson #define CIR_CR_COMMAND_INDEX 0x04 1819bdc79eaSJarod Wilson #define CIR_CR_IRCS 0x05 /* Before host writes command to IR, host 1829bdc79eaSJarod Wilson must set to 1. When host finshes write 1839bdc79eaSJarod Wilson command to IR, host must clear to 0. */ 1849bdc79eaSJarod Wilson #define CIR_CR_COMMAND_DATA 0x06 /* Host read or write comand data */ 1859bdc79eaSJarod Wilson #define CIR_CR_CLASS 0x07 /* 0xff = rx-only, 0x66 = rx + 2 tx, 1869bdc79eaSJarod Wilson 0x33 = rx + 1 tx */ 1879bdc79eaSJarod Wilson #define CIR_CR_DEV_EN 0x30 /* bit0 = 1 enables CIR */ 1889bdc79eaSJarod Wilson #define CIR_CR_BASE_ADDR_HI 0x60 /* MSB of CIR IO base addr */ 1899bdc79eaSJarod Wilson #define CIR_CR_BASE_ADDR_LO 0x61 /* LSB of CIR IO base addr */ 1909bdc79eaSJarod Wilson #define CIR_CR_IRQ_SEL 0x70 /* bits3-0 store CIR IRQ */ 1919bdc79eaSJarod Wilson #define CIR_CR_PSOUT_STATUS 0xf1 1929bdc79eaSJarod Wilson #define CIR_CR_WAKE_KEY3_ADDR 0xf8 1939bdc79eaSJarod Wilson #define CIR_CR_WAKE_KEY3_CODE 0xf9 1949bdc79eaSJarod Wilson #define CIR_CR_WAKE_KEY3_DC 0xfa 1959bdc79eaSJarod Wilson #define CIR_CR_WAKE_CONTROL 0xfb 1969bdc79eaSJarod Wilson #define CIR_CR_WAKE_KEY12_ADDR 0xfc 1979bdc79eaSJarod Wilson #define CIR_CR_WAKE_KEY4_ADDR 0xfd 1989bdc79eaSJarod Wilson #define CIR_CR_WAKE_KEY5_ADDR 0xfe 1999bdc79eaSJarod Wilson 2009bdc79eaSJarod Wilson #define CLASS_RX_ONLY 0xff 2019bdc79eaSJarod Wilson #define CLASS_RX_2TX 0x66 2029bdc79eaSJarod Wilson #define CLASS_RX_1TX 0x33 2039bdc79eaSJarod Wilson 2049bdc79eaSJarod Wilson /* CIR device registers */ 2059bdc79eaSJarod Wilson #define CIR_STATUS 0x00 2069bdc79eaSJarod Wilson #define CIR_RX_DATA 0x01 2079bdc79eaSJarod Wilson #define CIR_TX_CONTROL 0x02 2089bdc79eaSJarod Wilson #define CIR_TX_DATA 0x03 2099bdc79eaSJarod Wilson #define CIR_CONTROL 0x04 2109bdc79eaSJarod Wilson 2119bdc79eaSJarod Wilson /* Bits to enable CIR wake */ 2129bdc79eaSJarod Wilson #define LOGICAL_DEV_ACPI 0x01 2139bdc79eaSJarod Wilson #define LDEV_ACPI_WAKE_EN_REG 0xe8 2149bdc79eaSJarod Wilson #define ACPI_WAKE_EN_CIR_BIT 0x04 2159bdc79eaSJarod Wilson 2169bdc79eaSJarod Wilson #define LDEV_ACPI_PME_EN_REG 0xf0 2179bdc79eaSJarod Wilson #define LDEV_ACPI_PME_CLR_REG 0xf1 2189bdc79eaSJarod Wilson #define ACPI_PME_CIR_BIT 0x02 2199bdc79eaSJarod Wilson 2209bdc79eaSJarod Wilson #define LDEV_ACPI_STATE_REG 0xf4 2219bdc79eaSJarod Wilson #define ACPI_STATE_CIR_BIT 0x20 2229bdc79eaSJarod Wilson 2239bdc79eaSJarod Wilson /* 2249bdc79eaSJarod Wilson * CIR status register (0x00): 2259bdc79eaSJarod Wilson * 7 - CIR_IRQ_EN (1 = enable CIR IRQ, 0 = disable) 2269bdc79eaSJarod Wilson * 3 - TX_FINISH (1 when TX finished, write 1 to clear) 2279bdc79eaSJarod Wilson * 2 - TX_UNDERRUN (1 on TX underrun, write 1 to clear) 2289bdc79eaSJarod Wilson * 1 - RX_TIMEOUT (1 on RX timeout, write 1 to clear) 2299bdc79eaSJarod Wilson * 0 - RX_RECEIVE (1 on RX receive, write 1 to clear) 2309bdc79eaSJarod Wilson */ 2319bdc79eaSJarod Wilson #define CIR_STATUS_IRQ_EN 0x80 2329bdc79eaSJarod Wilson #define CIR_STATUS_TX_FINISH 0x08 2339bdc79eaSJarod Wilson #define CIR_STATUS_TX_UNDERRUN 0x04 2349bdc79eaSJarod Wilson #define CIR_STATUS_RX_TIMEOUT 0x02 2359bdc79eaSJarod Wilson #define CIR_STATUS_RX_RECEIVE 0x01 2369bdc79eaSJarod Wilson #define CIR_STATUS_IRQ_MASK 0x0f 2379bdc79eaSJarod Wilson 2389bdc79eaSJarod Wilson /* 2399bdc79eaSJarod Wilson * CIR TX control register (0x02): 2409bdc79eaSJarod Wilson * 7 - TX_START (1 to indicate TX start, auto-cleared when done) 2419bdc79eaSJarod Wilson * 6 - TX_END (1 to indicate TX data written to TX fifo) 2429bdc79eaSJarod Wilson */ 2439bdc79eaSJarod Wilson #define CIR_TX_CONTROL_TX_START 0x80 2449bdc79eaSJarod Wilson #define CIR_TX_CONTROL_TX_END 0x40 2459bdc79eaSJarod Wilson 246