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