18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * driver for ENE KB3926 B/C/D/E/F CIR (also known as ENE0XXX) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* hardware address */ 118c2ecf20Sopenharmony_ci#define ENE_STATUS 0 /* hardware status - unused */ 128c2ecf20Sopenharmony_ci#define ENE_ADDR_HI 1 /* hi byte of register address */ 138c2ecf20Sopenharmony_ci#define ENE_ADDR_LO 2 /* low byte of register address */ 148c2ecf20Sopenharmony_ci#define ENE_IO 3 /* read/write window */ 158c2ecf20Sopenharmony_ci#define ENE_IO_SIZE 4 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 8 bytes of samples, divided in 2 packets*/ 188c2ecf20Sopenharmony_ci#define ENE_FW_SAMPLE_BUFFER 0xF8F0 /* sample buffer */ 198c2ecf20Sopenharmony_ci#define ENE_FW_SAMPLE_SPACE 0x80 /* sample is space */ 208c2ecf20Sopenharmony_ci#define ENE_FW_PACKET_SIZE 4 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* first firmware flag register */ 238c2ecf20Sopenharmony_ci#define ENE_FW1 0xF8F8 /* flagr */ 248c2ecf20Sopenharmony_ci#define ENE_FW1_ENABLE 0x01 /* enable fw processing */ 258c2ecf20Sopenharmony_ci#define ENE_FW1_TXIRQ 0x02 /* TX interrupt pending */ 268c2ecf20Sopenharmony_ci#define ENE_FW1_HAS_EXTRA_BUF 0x04 /* fw uses extra buffer*/ 278c2ecf20Sopenharmony_ci#define ENE_FW1_EXTRA_BUF_HND 0x08 /* extra buffer handshake bit*/ 288c2ecf20Sopenharmony_ci#define ENE_FW1_LED_ON 0x10 /* turn on a led */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define ENE_FW1_WPATTERN 0x20 /* enable wake pattern */ 318c2ecf20Sopenharmony_ci#define ENE_FW1_WAKE 0x40 /* enable wake from S3 */ 328c2ecf20Sopenharmony_ci#define ENE_FW1_IRQ 0x80 /* enable interrupt */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* second firmware flag register */ 358c2ecf20Sopenharmony_ci#define ENE_FW2 0xF8F9 /* flagw */ 368c2ecf20Sopenharmony_ci#define ENE_FW2_BUF_WPTR 0x01 /* which half of the buffer to read */ 378c2ecf20Sopenharmony_ci#define ENE_FW2_RXIRQ 0x04 /* RX IRQ pending*/ 388c2ecf20Sopenharmony_ci#define ENE_FW2_GP0A 0x08 /* Use GPIO0A for demodulated input */ 398c2ecf20Sopenharmony_ci#define ENE_FW2_EMMITER1_CONN 0x10 /* TX emmiter 1 connected */ 408c2ecf20Sopenharmony_ci#define ENE_FW2_EMMITER2_CONN 0x20 /* TX emmiter 2 connected */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define ENE_FW2_FAN_INPUT 0x40 /* fan input used for demodulated data*/ 438c2ecf20Sopenharmony_ci#define ENE_FW2_LEARNING 0x80 /* hardware supports learning and TX */ 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* firmware RX pointer for new style buffer */ 468c2ecf20Sopenharmony_ci#define ENE_FW_RX_POINTER 0xF8FA 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* high parts of samples for fan input (8 samples)*/ 498c2ecf20Sopenharmony_ci#define ENE_FW_SMPL_BUF_FAN 0xF8FB 508c2ecf20Sopenharmony_ci#define ENE_FW_SMPL_BUF_FAN_PLS 0x8000 /* combined sample is pulse */ 518c2ecf20Sopenharmony_ci#define ENE_FW_SMPL_BUF_FAN_MSK 0x0FFF /* combined sample maximum value */ 528c2ecf20Sopenharmony_ci#define ENE_FW_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* transmitter ports */ 558c2ecf20Sopenharmony_ci#define ENE_GPIOFS1 0xFC01 568c2ecf20Sopenharmony_ci#define ENE_GPIOFS1_GPIO0D 0x20 /* enable tx output on GPIO0D */ 578c2ecf20Sopenharmony_ci#define ENE_GPIOFS8 0xFC08 588c2ecf20Sopenharmony_ci#define ENE_GPIOFS8_GPIO41 0x02 /* enable tx output on GPIO40 */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* IRQ registers block (for revision B) */ 618c2ecf20Sopenharmony_ci#define ENEB_IRQ 0xFD09 /* IRQ number */ 628c2ecf20Sopenharmony_ci#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */ 638c2ecf20Sopenharmony_ci#define ENEB_IRQ_STATUS 0xFD80 /* irq status */ 648c2ecf20Sopenharmony_ci#define ENEB_IRQ_STATUS_IR 0x20 /* IR irq */ 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* fan as input settings */ 678c2ecf20Sopenharmony_ci#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */ 688c2ecf20Sopenharmony_ci#define ENE_FAN_AS_IN1_EN 0xCD 698c2ecf20Sopenharmony_ci#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */ 708c2ecf20Sopenharmony_ci#define ENE_FAN_AS_IN2_EN 0x03 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* IRQ registers block (for revision C,D) */ 738c2ecf20Sopenharmony_ci#define ENE_IRQ 0xFE9B /* new irq settings register */ 748c2ecf20Sopenharmony_ci#define ENE_IRQ_MASK 0x0F /* irq number mask */ 758c2ecf20Sopenharmony_ci#define ENE_IRQ_UNK_EN 0x10 /* always enabled */ 768c2ecf20Sopenharmony_ci#define ENE_IRQ_STATUS 0x20 /* irq status and ACK */ 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* CIR Config register #1 */ 798c2ecf20Sopenharmony_ci#define ENE_CIRCFG 0xFEC0 808c2ecf20Sopenharmony_ci#define ENE_CIRCFG_RX_EN 0x01 /* RX enable */ 818c2ecf20Sopenharmony_ci#define ENE_CIRCFG_RX_IRQ 0x02 /* Enable hardware interrupt */ 828c2ecf20Sopenharmony_ci#define ENE_CIRCFG_REV_POL 0x04 /* Input polarity reversed */ 838c2ecf20Sopenharmony_ci#define ENE_CIRCFG_CARR_DEMOD 0x08 /* Enable carrier demodulator */ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define ENE_CIRCFG_TX_EN 0x10 /* TX enable */ 868c2ecf20Sopenharmony_ci#define ENE_CIRCFG_TX_IRQ 0x20 /* Send interrupt on TX done */ 878c2ecf20Sopenharmony_ci#define ENE_CIRCFG_TX_POL_REV 0x40 /* TX polarity reversed */ 888c2ecf20Sopenharmony_ci#define ENE_CIRCFG_TX_CARR 0x80 /* send TX carrier or not */ 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* CIR config register #2 */ 918c2ecf20Sopenharmony_ci#define ENE_CIRCFG2 0xFEC1 928c2ecf20Sopenharmony_ci#define ENE_CIRCFG2_RLC 0x00 938c2ecf20Sopenharmony_ci#define ENE_CIRCFG2_RC5 0x01 948c2ecf20Sopenharmony_ci#define ENE_CIRCFG2_RC6 0x02 958c2ecf20Sopenharmony_ci#define ENE_CIRCFG2_NEC 0x03 968c2ecf20Sopenharmony_ci#define ENE_CIRCFG2_CARR_DETECT 0x10 /* Enable carrier detection */ 978c2ecf20Sopenharmony_ci#define ENE_CIRCFG2_GPIO0A 0x20 /* Use GPIO0A instead of GPIO40 for input */ 988c2ecf20Sopenharmony_ci#define ENE_CIRCFG2_FAST_SAMPL1 0x40 /* Fast leading pulse detection for RC6 */ 998c2ecf20Sopenharmony_ci#define ENE_CIRCFG2_FAST_SAMPL2 0x80 /* Fast data detection for RC6 */ 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* Knobs for protocol decoding - will document when/if will use them */ 1028c2ecf20Sopenharmony_ci#define ENE_CIRPF 0xFEC2 1038c2ecf20Sopenharmony_ci#define ENE_CIRHIGH 0xFEC3 1048c2ecf20Sopenharmony_ci#define ENE_CIRBIT 0xFEC4 1058c2ecf20Sopenharmony_ci#define ENE_CIRSTART 0xFEC5 1068c2ecf20Sopenharmony_ci#define ENE_CIRSTART2 0xFEC6 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* Actual register which contains RLC RX data - read by firmware */ 1098c2ecf20Sopenharmony_ci#define ENE_CIRDAT_IN 0xFEC7 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* RLC configuration - sample period (1us resolution) + idle mode */ 1138c2ecf20Sopenharmony_ci#define ENE_CIRRLC_CFG 0xFEC8 1148c2ecf20Sopenharmony_ci#define ENE_CIRRLC_CFG_OVERFLOW 0x80 /* interrupt on overflows if set */ 1158c2ecf20Sopenharmony_ci#define ENE_DEFAULT_SAMPLE_PERIOD 50 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* Two byte RLC TX buffer */ 1188c2ecf20Sopenharmony_ci#define ENE_CIRRLC_OUT0 0xFEC9 1198c2ecf20Sopenharmony_ci#define ENE_CIRRLC_OUT1 0xFECA 1208c2ecf20Sopenharmony_ci#define ENE_CIRRLC_OUT_PULSE 0x80 /* Transmitted sample is pulse */ 1218c2ecf20Sopenharmony_ci#define ENE_CIRRLC_OUT_MASK 0x7F 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* Carrier detect setting 1258c2ecf20Sopenharmony_ci * Low nibble - number of carrier pulses to average 1268c2ecf20Sopenharmony_ci * High nibble - number of initial carrier pulses to discard 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci#define ENE_CIRCAR_PULS 0xFECB 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* detected RX carrier period (resolution: 500 ns) */ 1318c2ecf20Sopenharmony_ci#define ENE_CIRCAR_PRD 0xFECC 1328c2ecf20Sopenharmony_ci#define ENE_CIRCAR_PRD_VALID 0x80 /* data valid content valid */ 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* detected RX carrier pulse width (resolution: 500 ns) */ 1358c2ecf20Sopenharmony_ci#define ENE_CIRCAR_HPRD 0xFECD 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* TX period (resolution: 500 ns, minimum 2)*/ 1388c2ecf20Sopenharmony_ci#define ENE_CIRMOD_PRD 0xFECE 1398c2ecf20Sopenharmony_ci#define ENE_CIRMOD_PRD_POL 0x80 /* TX carrier polarity*/ 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci#define ENE_CIRMOD_PRD_MAX 0x7F /* 15.87 kHz */ 1428c2ecf20Sopenharmony_ci#define ENE_CIRMOD_PRD_MIN 0x02 /* 1 Mhz */ 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* TX pulse width (resolution: 500 ns)*/ 1458c2ecf20Sopenharmony_ci#define ENE_CIRMOD_HPRD 0xFECF 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/* Hardware versions */ 1488c2ecf20Sopenharmony_ci#define ENE_ECHV 0xFF00 /* hardware revision */ 1498c2ecf20Sopenharmony_ci#define ENE_PLLFRH 0xFF16 1508c2ecf20Sopenharmony_ci#define ENE_PLLFRL 0xFF17 1518c2ecf20Sopenharmony_ci#define ENE_DEFAULT_PLL_FREQ 1000 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci#define ENE_ECSTS 0xFF1D 1548c2ecf20Sopenharmony_ci#define ENE_ECSTS_RSRVD 0x04 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci#define ENE_ECVER_MAJOR 0xFF1E /* chip version */ 1578c2ecf20Sopenharmony_ci#define ENE_ECVER_MINOR 0xFF1F 1588c2ecf20Sopenharmony_ci#define ENE_HW_VER_OLD 0xFD00 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/******************************************************************************/ 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#define ENE_DRIVER_NAME "ene_ir" 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#define ENE_IRQ_RX 1 1658c2ecf20Sopenharmony_ci#define ENE_IRQ_TX 2 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci#define ENE_HW_B 1 /* 3926B */ 1688c2ecf20Sopenharmony_ci#define ENE_HW_C 2 /* 3926C */ 1698c2ecf20Sopenharmony_ci#define ENE_HW_D 3 /* 3926D or later */ 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#define __dbg(level, format, ...) \ 1728c2ecf20Sopenharmony_cido { \ 1738c2ecf20Sopenharmony_ci if (debug >= level) \ 1748c2ecf20Sopenharmony_ci pr_info(format "\n", ## __VA_ARGS__); \ 1758c2ecf20Sopenharmony_ci} while (0) 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#define dbg(format, ...) __dbg(1, format, ## __VA_ARGS__) 1788c2ecf20Sopenharmony_ci#define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__) 1798c2ecf20Sopenharmony_ci#define dbg_regs(format, ...) __dbg(3, format, ## __VA_ARGS__) 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistruct ene_device { 1828c2ecf20Sopenharmony_ci struct pnp_dev *pnp_dev; 1838c2ecf20Sopenharmony_ci struct rc_dev *rdev; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* hw IO settings */ 1868c2ecf20Sopenharmony_ci long hw_io; 1878c2ecf20Sopenharmony_ci int irq; 1888c2ecf20Sopenharmony_ci spinlock_t hw_lock; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* HW features */ 1918c2ecf20Sopenharmony_ci int hw_revision; /* hardware revision */ 1928c2ecf20Sopenharmony_ci bool hw_use_gpio_0a; /* gpio0a is demodulated input*/ 1938c2ecf20Sopenharmony_ci bool hw_extra_buffer; /* hardware has 'extra buffer' */ 1948c2ecf20Sopenharmony_ci bool hw_fan_input; /* fan input is IR data source */ 1958c2ecf20Sopenharmony_ci bool hw_learning_and_tx_capable; /* learning & tx capable */ 1968c2ecf20Sopenharmony_ci int pll_freq; 1978c2ecf20Sopenharmony_ci int buffer_len; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Extra RX buffer location */ 2008c2ecf20Sopenharmony_ci int extra_buf1_address; 2018c2ecf20Sopenharmony_ci int extra_buf1_len; 2028c2ecf20Sopenharmony_ci int extra_buf2_address; 2038c2ecf20Sopenharmony_ci int extra_buf2_len; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* HW state*/ 2068c2ecf20Sopenharmony_ci int r_pointer; /* pointer to next sample to read */ 2078c2ecf20Sopenharmony_ci int w_pointer; /* pointer to next sample hw will write */ 2088c2ecf20Sopenharmony_ci bool rx_fan_input_inuse; /* is fan input in use for rx*/ 2098c2ecf20Sopenharmony_ci int tx_reg; /* current reg used for TX */ 2108c2ecf20Sopenharmony_ci u8 saved_conf1; /* saved FEC0 reg */ 2118c2ecf20Sopenharmony_ci unsigned int tx_sample; /* current sample for TX */ 2128c2ecf20Sopenharmony_ci bool tx_sample_pulse; /* current sample is pulse */ 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* TX buffer */ 2158c2ecf20Sopenharmony_ci unsigned *tx_buffer; /* input samples buffer*/ 2168c2ecf20Sopenharmony_ci int tx_pos; /* position in that buffer */ 2178c2ecf20Sopenharmony_ci int tx_len; /* current len of tx buffer */ 2188c2ecf20Sopenharmony_ci int tx_done; /* done transmitting */ 2198c2ecf20Sopenharmony_ci /* one more sample pending*/ 2208c2ecf20Sopenharmony_ci struct completion tx_complete; /* TX completion */ 2218c2ecf20Sopenharmony_ci struct timer_list tx_sim_timer; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* TX settings */ 2248c2ecf20Sopenharmony_ci int tx_period; 2258c2ecf20Sopenharmony_ci int tx_duty_cycle; 2268c2ecf20Sopenharmony_ci int transmitter_mask; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* RX settings */ 2298c2ecf20Sopenharmony_ci bool learning_mode_enabled; /* learning input enabled */ 2308c2ecf20Sopenharmony_ci bool carrier_detect_enabled; /* carrier detect enabled */ 2318c2ecf20Sopenharmony_ci int rx_period_adjust; 2328c2ecf20Sopenharmony_ci bool rx_enabled; 2338c2ecf20Sopenharmony_ci}; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int ene_irq_status(struct ene_device *dev); 2368c2ecf20Sopenharmony_cistatic void ene_rx_read_hw_pointer(struct ene_device *dev); 237