18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for ITE Tech Inc. IT8712F/IT8512 CIR 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010 Juan Jesús García de Soria <skandalfo@gmail.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Inspired by the original lirc_it87 and lirc_ite8709 drivers, on top of the 88c2ecf20Sopenharmony_ci * skeleton provided by the nuvoton-cir driver. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * The lirc_it87 driver was originally written by Hans-Gunter Lutke Uphues 118c2ecf20Sopenharmony_ci * <hg_lu@web.de> in 2001, with enhancements by Christoph Bartelmus 128c2ecf20Sopenharmony_ci * <lirc@bartelmus.de>, Andrew Calkin <r_tay@hotmail.com> and James Edwards 138c2ecf20Sopenharmony_ci * <jimbo-lirc@edwardsclan.net>. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * The lirc_ite8709 driver was written by Grégory Lardière 168c2ecf20Sopenharmony_ci * <spmf2004-lirc@yahoo.fr> in 2008. 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/pnp.h> 228c2ecf20Sopenharmony_ci#include <linux/io.h> 238c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 248c2ecf20Sopenharmony_ci#include <linux/sched.h> 258c2ecf20Sopenharmony_ci#include <linux/delay.h> 268c2ecf20Sopenharmony_ci#include <linux/slab.h> 278c2ecf20Sopenharmony_ci#include <linux/input.h> 288c2ecf20Sopenharmony_ci#include <linux/bitops.h> 298c2ecf20Sopenharmony_ci#include <media/rc-core.h> 308c2ecf20Sopenharmony_ci#include <linux/pci_ids.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "ite-cir.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* module parameters */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* debug level */ 378c2ecf20Sopenharmony_cistatic int debug; 388c2ecf20Sopenharmony_cimodule_param(debug, int, S_IRUGO | S_IWUSR); 398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Enable debugging output"); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* low limit for RX carrier freq, Hz, 0 for no RX demodulation */ 428c2ecf20Sopenharmony_cistatic int rx_low_carrier_freq; 438c2ecf20Sopenharmony_cimodule_param(rx_low_carrier_freq, int, S_IRUGO | S_IWUSR); 448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rx_low_carrier_freq, "Override low RX carrier frequency, Hz, 0 for no RX demodulation"); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* high limit for RX carrier freq, Hz, 0 for no RX demodulation */ 478c2ecf20Sopenharmony_cistatic int rx_high_carrier_freq; 488c2ecf20Sopenharmony_cimodule_param(rx_high_carrier_freq, int, S_IRUGO | S_IWUSR); 498c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rx_high_carrier_freq, "Override high RX carrier frequency, Hz, 0 for no RX demodulation"); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* override tx carrier frequency */ 528c2ecf20Sopenharmony_cistatic int tx_carrier_freq; 538c2ecf20Sopenharmony_cimodule_param(tx_carrier_freq, int, S_IRUGO | S_IWUSR); 548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tx_carrier_freq, "Override TX carrier frequency, Hz"); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* override tx duty cycle */ 578c2ecf20Sopenharmony_cistatic int tx_duty_cycle; 588c2ecf20Sopenharmony_cimodule_param(tx_duty_cycle, int, S_IRUGO | S_IWUSR); 598c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tx_duty_cycle, "Override TX duty cycle, 1-100"); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* override default sample period */ 628c2ecf20Sopenharmony_cistatic long sample_period; 638c2ecf20Sopenharmony_cimodule_param(sample_period, long, S_IRUGO | S_IWUSR); 648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sample_period, "Override carrier sample period, us"); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* override detected model id */ 678c2ecf20Sopenharmony_cistatic int model_number = -1; 688c2ecf20Sopenharmony_cimodule_param(model_number, int, S_IRUGO | S_IWUSR); 698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(model_number, "Use this model number, don't autodetect"); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* HW-independent code functions */ 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* check whether carrier frequency is high frequency */ 758c2ecf20Sopenharmony_cistatic inline bool ite_is_high_carrier_freq(unsigned int freq) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci return freq >= ITE_HCF_MIN_CARRIER_FREQ; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* get the bits required to program the carrier frequency in CFQ bits, 818c2ecf20Sopenharmony_ci * unshifted */ 828c2ecf20Sopenharmony_cistatic u8 ite_get_carrier_freq_bits(unsigned int freq) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci if (ite_is_high_carrier_freq(freq)) { 858c2ecf20Sopenharmony_ci if (freq < 425000) 868c2ecf20Sopenharmony_ci return ITE_CFQ_400; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci else if (freq < 465000) 898c2ecf20Sopenharmony_ci return ITE_CFQ_450; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci else if (freq < 490000) 928c2ecf20Sopenharmony_ci return ITE_CFQ_480; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci else 958c2ecf20Sopenharmony_ci return ITE_CFQ_500; 968c2ecf20Sopenharmony_ci } else { 978c2ecf20Sopenharmony_ci /* trim to limits */ 988c2ecf20Sopenharmony_ci if (freq < ITE_LCF_MIN_CARRIER_FREQ) 998c2ecf20Sopenharmony_ci freq = ITE_LCF_MIN_CARRIER_FREQ; 1008c2ecf20Sopenharmony_ci if (freq > ITE_LCF_MAX_CARRIER_FREQ) 1018c2ecf20Sopenharmony_ci freq = ITE_LCF_MAX_CARRIER_FREQ; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* convert to kHz and subtract the base freq */ 1048c2ecf20Sopenharmony_ci freq = 1058c2ecf20Sopenharmony_ci DIV_ROUND_CLOSEST(freq - ITE_LCF_MIN_CARRIER_FREQ, 1068c2ecf20Sopenharmony_ci 1000); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return (u8) freq; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* get the bits required to program the pulse with in TXMPW */ 1138c2ecf20Sopenharmony_cistatic u8 ite_get_pulse_width_bits(unsigned int freq, int duty_cycle) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci unsigned long period_ns, on_ns; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* sanitize freq into range */ 1188c2ecf20Sopenharmony_ci if (freq < ITE_LCF_MIN_CARRIER_FREQ) 1198c2ecf20Sopenharmony_ci freq = ITE_LCF_MIN_CARRIER_FREQ; 1208c2ecf20Sopenharmony_ci if (freq > ITE_HCF_MAX_CARRIER_FREQ) 1218c2ecf20Sopenharmony_ci freq = ITE_HCF_MAX_CARRIER_FREQ; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci period_ns = 1000000000UL / freq; 1248c2ecf20Sopenharmony_ci on_ns = period_ns * duty_cycle / 100; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (ite_is_high_carrier_freq(freq)) { 1278c2ecf20Sopenharmony_ci if (on_ns < 750) 1288c2ecf20Sopenharmony_ci return ITE_TXMPW_A; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci else if (on_ns < 850) 1318c2ecf20Sopenharmony_ci return ITE_TXMPW_B; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci else if (on_ns < 950) 1348c2ecf20Sopenharmony_ci return ITE_TXMPW_C; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci else if (on_ns < 1080) 1378c2ecf20Sopenharmony_ci return ITE_TXMPW_D; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci else 1408c2ecf20Sopenharmony_ci return ITE_TXMPW_E; 1418c2ecf20Sopenharmony_ci } else { 1428c2ecf20Sopenharmony_ci if (on_ns < 6500) 1438c2ecf20Sopenharmony_ci return ITE_TXMPW_A; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci else if (on_ns < 7850) 1468c2ecf20Sopenharmony_ci return ITE_TXMPW_B; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci else if (on_ns < 9650) 1498c2ecf20Sopenharmony_ci return ITE_TXMPW_C; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci else if (on_ns < 11950) 1528c2ecf20Sopenharmony_ci return ITE_TXMPW_D; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci else 1558c2ecf20Sopenharmony_ci return ITE_TXMPW_E; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* decode raw bytes as received by the hardware, and push them to the ir-core 1608c2ecf20Sopenharmony_ci * layer */ 1618c2ecf20Sopenharmony_cistatic void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int 1628c2ecf20Sopenharmony_ci length) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci u32 sample_period; 1658c2ecf20Sopenharmony_ci unsigned long *ldata; 1668c2ecf20Sopenharmony_ci unsigned int next_one, next_zero, size; 1678c2ecf20Sopenharmony_ci struct ir_raw_event ev = {}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (length == 0) 1708c2ecf20Sopenharmony_ci return; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci sample_period = dev->params.sample_period; 1738c2ecf20Sopenharmony_ci ldata = (unsigned long *)data; 1748c2ecf20Sopenharmony_ci size = length << 3; 1758c2ecf20Sopenharmony_ci next_one = find_next_bit_le(ldata, size, 0); 1768c2ecf20Sopenharmony_ci if (next_one > 0) { 1778c2ecf20Sopenharmony_ci ev.pulse = true; 1788c2ecf20Sopenharmony_ci ev.duration = 1798c2ecf20Sopenharmony_ci ITE_BITS_TO_US(next_one, sample_period); 1808c2ecf20Sopenharmony_ci ir_raw_event_store_with_filter(dev->rdev, &ev); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci while (next_one < size) { 1848c2ecf20Sopenharmony_ci next_zero = find_next_zero_bit_le(ldata, size, next_one + 1); 1858c2ecf20Sopenharmony_ci ev.pulse = false; 1868c2ecf20Sopenharmony_ci ev.duration = ITE_BITS_TO_US(next_zero - next_one, sample_period); 1878c2ecf20Sopenharmony_ci ir_raw_event_store_with_filter(dev->rdev, &ev); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (next_zero < size) { 1908c2ecf20Sopenharmony_ci next_one = 1918c2ecf20Sopenharmony_ci find_next_bit_le(ldata, 1928c2ecf20Sopenharmony_ci size, 1938c2ecf20Sopenharmony_ci next_zero + 1); 1948c2ecf20Sopenharmony_ci ev.pulse = true; 1958c2ecf20Sopenharmony_ci ev.duration = 1968c2ecf20Sopenharmony_ci ITE_BITS_TO_US(next_one - next_zero, 1978c2ecf20Sopenharmony_ci sample_period); 1988c2ecf20Sopenharmony_ci ir_raw_event_store_with_filter 1998c2ecf20Sopenharmony_ci (dev->rdev, &ev); 2008c2ecf20Sopenharmony_ci } else 2018c2ecf20Sopenharmony_ci next_one = size; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci ir_raw_event_handle(dev->rdev); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci ite_dbg_verbose("decoded %d bytes.", length); 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/* set all the rx/tx carrier parameters; this must be called with the device 2108c2ecf20Sopenharmony_ci * spinlock held */ 2118c2ecf20Sopenharmony_cistatic void ite_set_carrier_params(struct ite_dev *dev) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci unsigned int freq, low_freq, high_freq; 2148c2ecf20Sopenharmony_ci int allowance; 2158c2ecf20Sopenharmony_ci bool use_demodulator; 2168c2ecf20Sopenharmony_ci bool for_tx = dev->transmitting; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (for_tx) { 2218c2ecf20Sopenharmony_ci /* we don't need no stinking calculations */ 2228c2ecf20Sopenharmony_ci freq = dev->params.tx_carrier_freq; 2238c2ecf20Sopenharmony_ci allowance = ITE_RXDCR_DEFAULT; 2248c2ecf20Sopenharmony_ci use_demodulator = false; 2258c2ecf20Sopenharmony_ci } else { 2268c2ecf20Sopenharmony_ci low_freq = dev->params.rx_low_carrier_freq; 2278c2ecf20Sopenharmony_ci high_freq = dev->params.rx_high_carrier_freq; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (low_freq == 0) { 2308c2ecf20Sopenharmony_ci /* don't demodulate */ 2318c2ecf20Sopenharmony_ci freq = 2328c2ecf20Sopenharmony_ci ITE_DEFAULT_CARRIER_FREQ; 2338c2ecf20Sopenharmony_ci allowance = ITE_RXDCR_DEFAULT; 2348c2ecf20Sopenharmony_ci use_demodulator = false; 2358c2ecf20Sopenharmony_ci } else { 2368c2ecf20Sopenharmony_ci /* calculate the middle freq */ 2378c2ecf20Sopenharmony_ci freq = (low_freq + high_freq) / 2; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* calculate the allowance */ 2408c2ecf20Sopenharmony_ci allowance = 2418c2ecf20Sopenharmony_ci DIV_ROUND_CLOSEST(10000 * (high_freq - low_freq), 2428c2ecf20Sopenharmony_ci ITE_RXDCR_PER_10000_STEP 2438c2ecf20Sopenharmony_ci * (high_freq + low_freq)); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (allowance < 1) 2468c2ecf20Sopenharmony_ci allowance = 1; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (allowance > ITE_RXDCR_MAX) 2498c2ecf20Sopenharmony_ci allowance = ITE_RXDCR_MAX; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci use_demodulator = true; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* set the carrier parameters in a device-dependent way */ 2568c2ecf20Sopenharmony_ci dev->params.set_carrier_params(dev, ite_is_high_carrier_freq(freq), 2578c2ecf20Sopenharmony_ci use_demodulator, ite_get_carrier_freq_bits(freq), allowance, 2588c2ecf20Sopenharmony_ci ite_get_pulse_width_bits(freq, dev->params.tx_duty_cycle)); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* interrupt service routine for incoming and outgoing CIR data */ 2628c2ecf20Sopenharmony_cistatic irqreturn_t ite_cir_isr(int irq, void *data) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct ite_dev *dev = data; 2658c2ecf20Sopenharmony_ci unsigned long flags; 2668c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_RETVAL(IRQ_NONE); 2678c2ecf20Sopenharmony_ci u8 rx_buf[ITE_RX_FIFO_LEN]; 2688c2ecf20Sopenharmony_ci int rx_bytes; 2698c2ecf20Sopenharmony_ci int iflags; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci ite_dbg_verbose("%s firing", __func__); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* grab the spinlock */ 2748c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* read the interrupt flags */ 2778c2ecf20Sopenharmony_ci iflags = dev->params.get_irq_causes(dev); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Check for RX overflow */ 2808c2ecf20Sopenharmony_ci if (iflags & ITE_IRQ_RX_FIFO_OVERRUN) { 2818c2ecf20Sopenharmony_ci dev_warn(&dev->rdev->dev, "receive overflow\n"); 2828c2ecf20Sopenharmony_ci ir_raw_event_reset(dev->rdev); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* check for the receive interrupt */ 2868c2ecf20Sopenharmony_ci if (iflags & (ITE_IRQ_RX_FIFO | ITE_IRQ_RX_FIFO_OVERRUN)) { 2878c2ecf20Sopenharmony_ci /* read the FIFO bytes */ 2888c2ecf20Sopenharmony_ci rx_bytes = 2898c2ecf20Sopenharmony_ci dev->params.get_rx_bytes(dev, rx_buf, 2908c2ecf20Sopenharmony_ci ITE_RX_FIFO_LEN); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (rx_bytes > 0) { 2938c2ecf20Sopenharmony_ci /* drop the spinlock, since the ir-core layer 2948c2ecf20Sopenharmony_ci * may call us back again through 2958c2ecf20Sopenharmony_ci * ite_s_idle() */ 2968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev-> 2978c2ecf20Sopenharmony_ci lock, 2988c2ecf20Sopenharmony_ci flags); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* decode the data we've just received */ 3018c2ecf20Sopenharmony_ci ite_decode_bytes(dev, rx_buf, 3028c2ecf20Sopenharmony_ci rx_bytes); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* reacquire the spinlock */ 3058c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, 3068c2ecf20Sopenharmony_ci flags); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* mark the interrupt as serviced */ 3098c2ecf20Sopenharmony_ci ret = IRQ_RETVAL(IRQ_HANDLED); 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci } else if (iflags & ITE_IRQ_TX_FIFO) { 3128c2ecf20Sopenharmony_ci /* FIFO space available interrupt */ 3138c2ecf20Sopenharmony_ci ite_dbg_verbose("got interrupt for TX FIFO"); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* wake any sleeping transmitter */ 3168c2ecf20Sopenharmony_ci wake_up_interruptible(&dev->tx_queue); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* mark the interrupt as serviced */ 3198c2ecf20Sopenharmony_ci ret = IRQ_RETVAL(IRQ_HANDLED); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* drop the spinlock */ 3238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci ite_dbg_verbose("%s done returning %d", __func__, (int)ret); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return ret; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci/* set the rx carrier freq range, guess it's in Hz... */ 3318c2ecf20Sopenharmony_cistatic int ite_set_rx_carrier_range(struct rc_dev *rcdev, u32 carrier_low, u32 3328c2ecf20Sopenharmony_ci carrier_high) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci unsigned long flags; 3358c2ecf20Sopenharmony_ci struct ite_dev *dev = rcdev->priv; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 3388c2ecf20Sopenharmony_ci dev->params.rx_low_carrier_freq = carrier_low; 3398c2ecf20Sopenharmony_ci dev->params.rx_high_carrier_freq = carrier_high; 3408c2ecf20Sopenharmony_ci ite_set_carrier_params(dev); 3418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci/* set the tx carrier freq, guess it's in Hz... */ 3478c2ecf20Sopenharmony_cistatic int ite_set_tx_carrier(struct rc_dev *rcdev, u32 carrier) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci unsigned long flags; 3508c2ecf20Sopenharmony_ci struct ite_dev *dev = rcdev->priv; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 3538c2ecf20Sopenharmony_ci dev->params.tx_carrier_freq = carrier; 3548c2ecf20Sopenharmony_ci ite_set_carrier_params(dev); 3558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/* set the tx duty cycle by controlling the pulse width */ 3618c2ecf20Sopenharmony_cistatic int ite_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci unsigned long flags; 3648c2ecf20Sopenharmony_ci struct ite_dev *dev = rcdev->priv; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 3678c2ecf20Sopenharmony_ci dev->params.tx_duty_cycle = duty_cycle; 3688c2ecf20Sopenharmony_ci ite_set_carrier_params(dev); 3698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci/* transmit out IR pulses; what you get here is a batch of alternating 3758c2ecf20Sopenharmony_ci * pulse/space/pulse/space lengths that we should write out completely through 3768c2ecf20Sopenharmony_ci * the FIFO, blocking on a full FIFO */ 3778c2ecf20Sopenharmony_cistatic int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci unsigned long flags; 3808c2ecf20Sopenharmony_ci struct ite_dev *dev = rcdev->priv; 3818c2ecf20Sopenharmony_ci bool is_pulse = false; 3828c2ecf20Sopenharmony_ci int remaining_us, fifo_avail, fifo_remaining, last_idx = 0; 3838c2ecf20Sopenharmony_ci int max_rle_us, next_rle_us; 3848c2ecf20Sopenharmony_ci int ret = n; 3858c2ecf20Sopenharmony_ci u8 last_sent[ITE_TX_FIFO_LEN]; 3868c2ecf20Sopenharmony_ci u8 val; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* clear the array just in case */ 3918c2ecf20Sopenharmony_ci memset(last_sent, 0, sizeof(last_sent)); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* let everybody know we're now transmitting */ 3968c2ecf20Sopenharmony_ci dev->transmitting = true; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* and set the carrier values for transmission */ 3998c2ecf20Sopenharmony_ci ite_set_carrier_params(dev); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* calculate how much time we can send in one byte */ 4028c2ecf20Sopenharmony_ci max_rle_us = 4038c2ecf20Sopenharmony_ci (ITE_BAUDRATE_DIVISOR * dev->params.sample_period * 4048c2ecf20Sopenharmony_ci ITE_TX_MAX_RLE) / 1000; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* disable the receiver */ 4078c2ecf20Sopenharmony_ci dev->params.disable_rx(dev); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* this is where we'll begin filling in the FIFO, until it's full. 4108c2ecf20Sopenharmony_ci * then we'll just activate the interrupt, wait for it to wake us up 4118c2ecf20Sopenharmony_ci * again, disable it, continue filling the FIFO... until everything 4128c2ecf20Sopenharmony_ci * has been pushed out */ 4138c2ecf20Sopenharmony_ci fifo_avail = 4148c2ecf20Sopenharmony_ci ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci while (n > 0 && dev->in_use) { 4178c2ecf20Sopenharmony_ci /* transmit the next sample */ 4188c2ecf20Sopenharmony_ci is_pulse = !is_pulse; 4198c2ecf20Sopenharmony_ci remaining_us = *(txbuf++); 4208c2ecf20Sopenharmony_ci n--; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci ite_dbg("%s: %ld", 4238c2ecf20Sopenharmony_ci ((is_pulse) ? "pulse" : "space"), 4248c2ecf20Sopenharmony_ci (long int) 4258c2ecf20Sopenharmony_ci remaining_us); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* repeat while the pulse is non-zero length */ 4288c2ecf20Sopenharmony_ci while (remaining_us > 0 && dev->in_use) { 4298c2ecf20Sopenharmony_ci if (remaining_us > max_rle_us) 4308c2ecf20Sopenharmony_ci next_rle_us = max_rle_us; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci else 4338c2ecf20Sopenharmony_ci next_rle_us = remaining_us; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci remaining_us -= next_rle_us; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* check what's the length we have to pump out */ 4388c2ecf20Sopenharmony_ci val = (ITE_TX_MAX_RLE * next_rle_us) / max_rle_us; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* put it into the sent buffer */ 4418c2ecf20Sopenharmony_ci last_sent[last_idx++] = val; 4428c2ecf20Sopenharmony_ci last_idx &= (ITE_TX_FIFO_LEN); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* encode it for 7 bits */ 4458c2ecf20Sopenharmony_ci val = (val - 1) & ITE_TX_RLE_MASK; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* take into account pulse/space prefix */ 4488c2ecf20Sopenharmony_ci if (is_pulse) 4498c2ecf20Sopenharmony_ci val |= ITE_TX_PULSE; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci else 4528c2ecf20Sopenharmony_ci val |= ITE_TX_SPACE; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* 4558c2ecf20Sopenharmony_ci * if we get to 0 available, read again, just in case 4568c2ecf20Sopenharmony_ci * some other slot got freed 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_ci if (fifo_avail <= 0) 4598c2ecf20Sopenharmony_ci fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* if it's still full */ 4628c2ecf20Sopenharmony_ci if (fifo_avail <= 0) { 4638c2ecf20Sopenharmony_ci /* enable the tx interrupt */ 4648c2ecf20Sopenharmony_ci dev->params. 4658c2ecf20Sopenharmony_ci enable_tx_interrupt(dev); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* drop the spinlock */ 4688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* wait for the FIFO to empty enough */ 4718c2ecf20Sopenharmony_ci wait_event_interruptible(dev->tx_queue, (fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev)) >= 8); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* get the spinlock again */ 4748c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* disable the tx interrupt again. */ 4778c2ecf20Sopenharmony_ci dev->params. 4788c2ecf20Sopenharmony_ci disable_tx_interrupt(dev); 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* now send the byte through the FIFO */ 4828c2ecf20Sopenharmony_ci dev->params.put_tx_byte(dev, val); 4838c2ecf20Sopenharmony_ci fifo_avail--; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* wait and don't return until the whole FIFO has been sent out; 4888c2ecf20Sopenharmony_ci * otherwise we could configure the RX carrier params instead of the 4898c2ecf20Sopenharmony_ci * TX ones while the transmission is still being performed! */ 4908c2ecf20Sopenharmony_ci fifo_remaining = dev->params.get_tx_used_slots(dev); 4918c2ecf20Sopenharmony_ci remaining_us = 0; 4928c2ecf20Sopenharmony_ci while (fifo_remaining > 0) { 4938c2ecf20Sopenharmony_ci fifo_remaining--; 4948c2ecf20Sopenharmony_ci last_idx--; 4958c2ecf20Sopenharmony_ci last_idx &= (ITE_TX_FIFO_LEN - 1); 4968c2ecf20Sopenharmony_ci remaining_us += last_sent[last_idx]; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci remaining_us = (remaining_us * max_rle_us) / (ITE_TX_MAX_RLE); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* drop the spinlock while we sleep */ 5018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* sleep remaining_us microseconds */ 5048c2ecf20Sopenharmony_ci mdelay(DIV_ROUND_UP(remaining_us, 1000)); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* reacquire the spinlock */ 5078c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* now we're not transmitting anymore */ 5108c2ecf20Sopenharmony_ci dev->transmitting = false; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* and set the carrier values for reception */ 5138c2ecf20Sopenharmony_ci ite_set_carrier_params(dev); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* re-enable the receiver */ 5168c2ecf20Sopenharmony_ci if (dev->in_use) 5178c2ecf20Sopenharmony_ci dev->params.enable_rx(dev); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* notify transmission end */ 5208c2ecf20Sopenharmony_ci wake_up_interruptible(&dev->tx_ended); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci return ret; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/* idle the receiver if needed */ 5288c2ecf20Sopenharmony_cistatic void ite_s_idle(struct rc_dev *rcdev, bool enable) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci unsigned long flags; 5318c2ecf20Sopenharmony_ci struct ite_dev *dev = rcdev->priv; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (enable) { 5368c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 5378c2ecf20Sopenharmony_ci dev->params.idle_rx(dev); 5388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci/* IT8712F HW-specific functions */ 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci/* retrieve a bitmask of the current causes for a pending interrupt; this may 5468c2ecf20Sopenharmony_ci * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN 5478c2ecf20Sopenharmony_ci * */ 5488c2ecf20Sopenharmony_cistatic int it87_get_irq_causes(struct ite_dev *dev) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci u8 iflags; 5518c2ecf20Sopenharmony_ci int ret = 0; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci /* read the interrupt flags */ 5568c2ecf20Sopenharmony_ci iflags = inb(dev->cir_addr + IT87_IIR) & IT87_II; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci switch (iflags) { 5598c2ecf20Sopenharmony_ci case IT87_II_RXDS: 5608c2ecf20Sopenharmony_ci ret = ITE_IRQ_RX_FIFO; 5618c2ecf20Sopenharmony_ci break; 5628c2ecf20Sopenharmony_ci case IT87_II_RXFO: 5638c2ecf20Sopenharmony_ci ret = ITE_IRQ_RX_FIFO_OVERRUN; 5648c2ecf20Sopenharmony_ci break; 5658c2ecf20Sopenharmony_ci case IT87_II_TXLDL: 5668c2ecf20Sopenharmony_ci ret = ITE_IRQ_TX_FIFO; 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return ret; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci/* set the carrier parameters; to be called with the spinlock held */ 5748c2ecf20Sopenharmony_cistatic void it87_set_carrier_params(struct ite_dev *dev, bool high_freq, 5758c2ecf20Sopenharmony_ci bool use_demodulator, 5768c2ecf20Sopenharmony_ci u8 carrier_freq_bits, u8 allowance_bits, 5778c2ecf20Sopenharmony_ci u8 pulse_width_bits) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci u8 val; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* program the RCR register */ 5848c2ecf20Sopenharmony_ci val = inb(dev->cir_addr + IT87_RCR) 5858c2ecf20Sopenharmony_ci & ~(IT87_HCFS | IT87_RXEND | IT87_RXDCR); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (high_freq) 5888c2ecf20Sopenharmony_ci val |= IT87_HCFS; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (use_demodulator) 5918c2ecf20Sopenharmony_ci val |= IT87_RXEND; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci val |= allowance_bits; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci outb(val, dev->cir_addr + IT87_RCR); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* program the TCR2 register */ 5988c2ecf20Sopenharmony_ci outb((carrier_freq_bits << IT87_CFQ_SHIFT) | pulse_width_bits, 5998c2ecf20Sopenharmony_ci dev->cir_addr + IT87_TCR2); 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock 6038c2ecf20Sopenharmony_ci * held */ 6048c2ecf20Sopenharmony_cistatic int it87_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci int fifo, read = 0; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* read how many bytes are still in the FIFO */ 6118c2ecf20Sopenharmony_ci fifo = inb(dev->cir_addr + IT87_RSR) & IT87_RXFBC; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci while (fifo > 0 && buf_size > 0) { 6148c2ecf20Sopenharmony_ci *(buf++) = inb(dev->cir_addr + IT87_DR); 6158c2ecf20Sopenharmony_ci fifo--; 6168c2ecf20Sopenharmony_ci read++; 6178c2ecf20Sopenharmony_ci buf_size--; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci return read; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci/* return how many bytes are still in the FIFO; this will be called 6248c2ecf20Sopenharmony_ci * with the device spinlock NOT HELD while waiting for the TX FIFO to get 6258c2ecf20Sopenharmony_ci * empty; let's expect this won't be a problem */ 6268c2ecf20Sopenharmony_cistatic int it87_get_tx_used_slots(struct ite_dev *dev) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return inb(dev->cir_addr + IT87_TSR) & IT87_TXFBC; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci/* put a byte to the TX fifo; this should be called with the spinlock held */ 6348c2ecf20Sopenharmony_cistatic void it87_put_tx_byte(struct ite_dev *dev, u8 value) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci outb(value, dev->cir_addr + IT87_DR); 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci/* idle the receiver so that we won't receive samples until another 6408c2ecf20Sopenharmony_ci pulse is detected; this must be called with the device spinlock held */ 6418c2ecf20Sopenharmony_cistatic void it87_idle_rx(struct ite_dev *dev) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* disable streaming by clearing RXACT writing it as 1 */ 6468c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT87_RCR) | IT87_RXACT, 6478c2ecf20Sopenharmony_ci dev->cir_addr + IT87_RCR); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* clear the FIFO */ 6508c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT87_TCR1) | IT87_FIFOCLR, 6518c2ecf20Sopenharmony_ci dev->cir_addr + IT87_TCR1); 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci/* disable the receiver; this must be called with the device spinlock held */ 6558c2ecf20Sopenharmony_cistatic void it87_disable_rx(struct ite_dev *dev) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* disable the receiver interrupts */ 6608c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT87_IER) & ~(IT87_RDAIE | IT87_RFOIE), 6618c2ecf20Sopenharmony_ci dev->cir_addr + IT87_IER); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* disable the receiver */ 6648c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT87_RCR) & ~IT87_RXEN, 6658c2ecf20Sopenharmony_ci dev->cir_addr + IT87_RCR); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci /* clear the FIFO and RXACT (actually RXACT should have been cleared 6688c2ecf20Sopenharmony_ci * in the previous outb() call) */ 6698c2ecf20Sopenharmony_ci it87_idle_rx(dev); 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci/* enable the receiver; this must be called with the device spinlock held */ 6738c2ecf20Sopenharmony_cistatic void it87_enable_rx(struct ite_dev *dev) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* enable the receiver by setting RXEN */ 6788c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT87_RCR) | IT87_RXEN, 6798c2ecf20Sopenharmony_ci dev->cir_addr + IT87_RCR); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci /* just prepare it to idle for the next reception */ 6828c2ecf20Sopenharmony_ci it87_idle_rx(dev); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* enable the receiver interrupts and master enable flag */ 6858c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT87_IER) | IT87_RDAIE | IT87_RFOIE | IT87_IEC, 6868c2ecf20Sopenharmony_ci dev->cir_addr + IT87_IER); 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci/* disable the transmitter interrupt; this must be called with the device 6908c2ecf20Sopenharmony_ci * spinlock held */ 6918c2ecf20Sopenharmony_cistatic void it87_disable_tx_interrupt(struct ite_dev *dev) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* disable the transmitter interrupts */ 6968c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT87_IER) & ~IT87_TLDLIE, 6978c2ecf20Sopenharmony_ci dev->cir_addr + IT87_IER); 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci/* enable the transmitter interrupt; this must be called with the device 7018c2ecf20Sopenharmony_ci * spinlock held */ 7028c2ecf20Sopenharmony_cistatic void it87_enable_tx_interrupt(struct ite_dev *dev) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* enable the transmitter interrupts and master enable flag */ 7078c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT87_IER) | IT87_TLDLIE | IT87_IEC, 7088c2ecf20Sopenharmony_ci dev->cir_addr + IT87_IER); 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci/* disable the device; this must be called with the device spinlock held */ 7128c2ecf20Sopenharmony_cistatic void it87_disable(struct ite_dev *dev) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* clear out all interrupt enable flags */ 7178c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT87_IER) & 7188c2ecf20Sopenharmony_ci ~(IT87_IEC | IT87_RFOIE | IT87_RDAIE | IT87_TLDLIE), 7198c2ecf20Sopenharmony_ci dev->cir_addr + IT87_IER); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* disable the receiver */ 7228c2ecf20Sopenharmony_ci it87_disable_rx(dev); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* erase the FIFO */ 7258c2ecf20Sopenharmony_ci outb(IT87_FIFOCLR | inb(dev->cir_addr + IT87_TCR1), 7268c2ecf20Sopenharmony_ci dev->cir_addr + IT87_TCR1); 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci/* initialize the hardware */ 7308c2ecf20Sopenharmony_cistatic void it87_init_hardware(struct ite_dev *dev) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* enable just the baud rate divisor register, 7358c2ecf20Sopenharmony_ci disabling all the interrupts at the same time */ 7368c2ecf20Sopenharmony_ci outb((inb(dev->cir_addr + IT87_IER) & 7378c2ecf20Sopenharmony_ci ~(IT87_IEC | IT87_RFOIE | IT87_RDAIE | IT87_TLDLIE)) | IT87_BR, 7388c2ecf20Sopenharmony_ci dev->cir_addr + IT87_IER); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci /* write out the baud rate divisor */ 7418c2ecf20Sopenharmony_ci outb(ITE_BAUDRATE_DIVISOR & 0xff, dev->cir_addr + IT87_BDLR); 7428c2ecf20Sopenharmony_ci outb((ITE_BAUDRATE_DIVISOR >> 8) & 0xff, dev->cir_addr + IT87_BDHR); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* disable the baud rate divisor register again */ 7458c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT87_IER) & ~IT87_BR, 7468c2ecf20Sopenharmony_ci dev->cir_addr + IT87_IER); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* program the RCR register defaults */ 7498c2ecf20Sopenharmony_ci outb(ITE_RXDCR_DEFAULT, dev->cir_addr + IT87_RCR); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* program the TCR1 register */ 7528c2ecf20Sopenharmony_ci outb(IT87_TXMPM_DEFAULT | IT87_TXENDF | IT87_TXRLE 7538c2ecf20Sopenharmony_ci | IT87_FIFOTL_DEFAULT | IT87_FIFOCLR, 7548c2ecf20Sopenharmony_ci dev->cir_addr + IT87_TCR1); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* program the carrier parameters */ 7578c2ecf20Sopenharmony_ci ite_set_carrier_params(dev); 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci/* IT8512F on ITE8708 HW-specific functions */ 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci/* retrieve a bitmask of the current causes for a pending interrupt; this may 7638c2ecf20Sopenharmony_ci * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN 7648c2ecf20Sopenharmony_ci * */ 7658c2ecf20Sopenharmony_cistatic int it8708_get_irq_causes(struct ite_dev *dev) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci u8 iflags; 7688c2ecf20Sopenharmony_ci int ret = 0; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* read the interrupt flags */ 7738c2ecf20Sopenharmony_ci iflags = inb(dev->cir_addr + IT8708_C0IIR); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (iflags & IT85_TLDLI) 7768c2ecf20Sopenharmony_ci ret |= ITE_IRQ_TX_FIFO; 7778c2ecf20Sopenharmony_ci if (iflags & IT85_RDAI) 7788c2ecf20Sopenharmony_ci ret |= ITE_IRQ_RX_FIFO; 7798c2ecf20Sopenharmony_ci if (iflags & IT85_RFOI) 7808c2ecf20Sopenharmony_ci ret |= ITE_IRQ_RX_FIFO_OVERRUN; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci return ret; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci/* set the carrier parameters; to be called with the spinlock held */ 7868c2ecf20Sopenharmony_cistatic void it8708_set_carrier_params(struct ite_dev *dev, bool high_freq, 7878c2ecf20Sopenharmony_ci bool use_demodulator, 7888c2ecf20Sopenharmony_ci u8 carrier_freq_bits, u8 allowance_bits, 7898c2ecf20Sopenharmony_ci u8 pulse_width_bits) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci u8 val; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci /* program the C0CFR register, with HRAE=1 */ 7968c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_BANKSEL) | IT8708_HRAE, 7978c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_BANKSEL); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci val = (inb(dev->cir_addr + IT8708_C0CFR) 8008c2ecf20Sopenharmony_ci & ~(IT85_HCFS | IT85_CFQ)) | carrier_freq_bits; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci if (high_freq) 8038c2ecf20Sopenharmony_ci val |= IT85_HCFS; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci outb(val, dev->cir_addr + IT8708_C0CFR); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_BANKSEL) & ~IT8708_HRAE, 8088c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_BANKSEL); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* program the C0RCR register */ 8118c2ecf20Sopenharmony_ci val = inb(dev->cir_addr + IT8708_C0RCR) 8128c2ecf20Sopenharmony_ci & ~(IT85_RXEND | IT85_RXDCR); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (use_demodulator) 8158c2ecf20Sopenharmony_ci val |= IT85_RXEND; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci val |= allowance_bits; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci outb(val, dev->cir_addr + IT8708_C0RCR); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci /* program the C0TCR register */ 8228c2ecf20Sopenharmony_ci val = inb(dev->cir_addr + IT8708_C0TCR) & ~IT85_TXMPW; 8238c2ecf20Sopenharmony_ci val |= pulse_width_bits; 8248c2ecf20Sopenharmony_ci outb(val, dev->cir_addr + IT8708_C0TCR); 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock 8288c2ecf20Sopenharmony_ci * held */ 8298c2ecf20Sopenharmony_cistatic int it8708_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci int fifo, read = 0; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci /* read how many bytes are still in the FIFO */ 8368c2ecf20Sopenharmony_ci fifo = inb(dev->cir_addr + IT8708_C0RFSR) & IT85_RXFBC; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci while (fifo > 0 && buf_size > 0) { 8398c2ecf20Sopenharmony_ci *(buf++) = inb(dev->cir_addr + IT8708_C0DR); 8408c2ecf20Sopenharmony_ci fifo--; 8418c2ecf20Sopenharmony_ci read++; 8428c2ecf20Sopenharmony_ci buf_size--; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci return read; 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci/* return how many bytes are still in the FIFO; this will be called 8498c2ecf20Sopenharmony_ci * with the device spinlock NOT HELD while waiting for the TX FIFO to get 8508c2ecf20Sopenharmony_ci * empty; let's expect this won't be a problem */ 8518c2ecf20Sopenharmony_cistatic int it8708_get_tx_used_slots(struct ite_dev *dev) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci return inb(dev->cir_addr + IT8708_C0TFSR) & IT85_TXFBC; 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci/* put a byte to the TX fifo; this should be called with the spinlock held */ 8598c2ecf20Sopenharmony_cistatic void it8708_put_tx_byte(struct ite_dev *dev, u8 value) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci outb(value, dev->cir_addr + IT8708_C0DR); 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci/* idle the receiver so that we won't receive samples until another 8658c2ecf20Sopenharmony_ci pulse is detected; this must be called with the device spinlock held */ 8668c2ecf20Sopenharmony_cistatic void it8708_idle_rx(struct ite_dev *dev) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci /* disable streaming by clearing RXACT writing it as 1 */ 8718c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_C0RCR) | IT85_RXACT, 8728c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0RCR); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* clear the FIFO */ 8758c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_C0MSTCR) | IT85_FIFOCLR, 8768c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0MSTCR); 8778c2ecf20Sopenharmony_ci} 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci/* disable the receiver; this must be called with the device spinlock held */ 8808c2ecf20Sopenharmony_cistatic void it8708_disable_rx(struct ite_dev *dev) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci /* disable the receiver interrupts */ 8858c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_C0IER) & 8868c2ecf20Sopenharmony_ci ~(IT85_RDAIE | IT85_RFOIE), 8878c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0IER); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci /* disable the receiver */ 8908c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_C0RCR) & ~IT85_RXEN, 8918c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0RCR); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci /* clear the FIFO and RXACT (actually RXACT should have been cleared 8948c2ecf20Sopenharmony_ci * in the previous outb() call) */ 8958c2ecf20Sopenharmony_ci it8708_idle_rx(dev); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci/* enable the receiver; this must be called with the device spinlock held */ 8998c2ecf20Sopenharmony_cistatic void it8708_enable_rx(struct ite_dev *dev) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci /* enable the receiver by setting RXEN */ 9048c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_C0RCR) | IT85_RXEN, 9058c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0RCR); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci /* just prepare it to idle for the next reception */ 9088c2ecf20Sopenharmony_ci it8708_idle_rx(dev); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* enable the receiver interrupts and master enable flag */ 9118c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_C0IER) 9128c2ecf20Sopenharmony_ci |IT85_RDAIE | IT85_RFOIE | IT85_IEC, 9138c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0IER); 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci/* disable the transmitter interrupt; this must be called with the device 9178c2ecf20Sopenharmony_ci * spinlock held */ 9188c2ecf20Sopenharmony_cistatic void it8708_disable_tx_interrupt(struct ite_dev *dev) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* disable the transmitter interrupts */ 9238c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_C0IER) & ~IT85_TLDLIE, 9248c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0IER); 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci/* enable the transmitter interrupt; this must be called with the device 9288c2ecf20Sopenharmony_ci * spinlock held */ 9298c2ecf20Sopenharmony_cistatic void it8708_enable_tx_interrupt(struct ite_dev *dev) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci /* enable the transmitter interrupts and master enable flag */ 9348c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_C0IER) 9358c2ecf20Sopenharmony_ci |IT85_TLDLIE | IT85_IEC, 9368c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0IER); 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci/* disable the device; this must be called with the device spinlock held */ 9408c2ecf20Sopenharmony_cistatic void it8708_disable(struct ite_dev *dev) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* clear out all interrupt enable flags */ 9458c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_C0IER) & 9468c2ecf20Sopenharmony_ci ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), 9478c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0IER); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci /* disable the receiver */ 9508c2ecf20Sopenharmony_ci it8708_disable_rx(dev); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* erase the FIFO */ 9538c2ecf20Sopenharmony_ci outb(IT85_FIFOCLR | inb(dev->cir_addr + IT8708_C0MSTCR), 9548c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0MSTCR); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci/* initialize the hardware */ 9588c2ecf20Sopenharmony_cistatic void it8708_init_hardware(struct ite_dev *dev) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci /* disable all the interrupts */ 9638c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_C0IER) & 9648c2ecf20Sopenharmony_ci ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), 9658c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0IER); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* program the baud rate divisor */ 9688c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_BANKSEL) | IT8708_HRAE, 9698c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_BANKSEL); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci outb(ITE_BAUDRATE_DIVISOR & 0xff, dev->cir_addr + IT8708_C0BDLR); 9728c2ecf20Sopenharmony_ci outb((ITE_BAUDRATE_DIVISOR >> 8) & 0xff, 9738c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0BDHR); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci outb(inb(dev->cir_addr + IT8708_BANKSEL) & ~IT8708_HRAE, 9768c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_BANKSEL); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci /* program the C0MSTCR register defaults */ 9798c2ecf20Sopenharmony_ci outb((inb(dev->cir_addr + IT8708_C0MSTCR) & 9808c2ecf20Sopenharmony_ci ~(IT85_ILSEL | IT85_ILE | IT85_FIFOTL | 9818c2ecf20Sopenharmony_ci IT85_FIFOCLR | IT85_RESET)) | 9828c2ecf20Sopenharmony_ci IT85_FIFOTL_DEFAULT, 9838c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0MSTCR); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci /* program the C0RCR register defaults */ 9868c2ecf20Sopenharmony_ci outb((inb(dev->cir_addr + IT8708_C0RCR) & 9878c2ecf20Sopenharmony_ci ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND | 9888c2ecf20Sopenharmony_ci IT85_RXACT | IT85_RXDCR)) | 9898c2ecf20Sopenharmony_ci ITE_RXDCR_DEFAULT, 9908c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0RCR); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci /* program the C0TCR register defaults */ 9938c2ecf20Sopenharmony_ci outb((inb(dev->cir_addr + IT8708_C0TCR) & 9948c2ecf20Sopenharmony_ci ~(IT85_TXMPM | IT85_TXMPW)) 9958c2ecf20Sopenharmony_ci |IT85_TXRLE | IT85_TXENDF | 9968c2ecf20Sopenharmony_ci IT85_TXMPM_DEFAULT | IT85_TXMPW_DEFAULT, 9978c2ecf20Sopenharmony_ci dev->cir_addr + IT8708_C0TCR); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci /* program the carrier parameters */ 10008c2ecf20Sopenharmony_ci ite_set_carrier_params(dev); 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci/* IT8512F on ITE8709 HW-specific functions */ 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci/* read a byte from the SRAM module */ 10068c2ecf20Sopenharmony_cistatic inline u8 it8709_rm(struct ite_dev *dev, int index) 10078c2ecf20Sopenharmony_ci{ 10088c2ecf20Sopenharmony_ci outb(index, dev->cir_addr + IT8709_RAM_IDX); 10098c2ecf20Sopenharmony_ci return inb(dev->cir_addr + IT8709_RAM_VAL); 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci/* write a byte to the SRAM module */ 10138c2ecf20Sopenharmony_cistatic inline void it8709_wm(struct ite_dev *dev, u8 val, int index) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci outb(index, dev->cir_addr + IT8709_RAM_IDX); 10168c2ecf20Sopenharmony_ci outb(val, dev->cir_addr + IT8709_RAM_VAL); 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic void it8709_wait(struct ite_dev *dev) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci int i = 0; 10228c2ecf20Sopenharmony_ci /* 10238c2ecf20Sopenharmony_ci * loop until device tells it's ready to continue 10248c2ecf20Sopenharmony_ci * iterations count is usually ~750 but can sometimes achieve 13000 10258c2ecf20Sopenharmony_ci */ 10268c2ecf20Sopenharmony_ci for (i = 0; i < 15000; i++) { 10278c2ecf20Sopenharmony_ci udelay(2); 10288c2ecf20Sopenharmony_ci if (it8709_rm(dev, IT8709_MODE) == IT8709_IDLE) 10298c2ecf20Sopenharmony_ci break; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci/* read the value of a CIR register */ 10348c2ecf20Sopenharmony_cistatic u8 it8709_rr(struct ite_dev *dev, int index) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci /* just wait in case the previous access was a write */ 10378c2ecf20Sopenharmony_ci it8709_wait(dev); 10388c2ecf20Sopenharmony_ci it8709_wm(dev, index, IT8709_REG_IDX); 10398c2ecf20Sopenharmony_ci it8709_wm(dev, IT8709_READ, IT8709_MODE); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* wait for the read data to be available */ 10428c2ecf20Sopenharmony_ci it8709_wait(dev); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci /* return the read value */ 10458c2ecf20Sopenharmony_ci return it8709_rm(dev, IT8709_REG_VAL); 10468c2ecf20Sopenharmony_ci} 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci/* write the value of a CIR register */ 10498c2ecf20Sopenharmony_cistatic void it8709_wr(struct ite_dev *dev, u8 val, int index) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci /* we wait before writing, and not afterwards, since this allows us to 10528c2ecf20Sopenharmony_ci * pipeline the host CPU with the microcontroller */ 10538c2ecf20Sopenharmony_ci it8709_wait(dev); 10548c2ecf20Sopenharmony_ci it8709_wm(dev, val, IT8709_REG_VAL); 10558c2ecf20Sopenharmony_ci it8709_wm(dev, index, IT8709_REG_IDX); 10568c2ecf20Sopenharmony_ci it8709_wm(dev, IT8709_WRITE, IT8709_MODE); 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci/* retrieve a bitmask of the current causes for a pending interrupt; this may 10608c2ecf20Sopenharmony_ci * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN 10618c2ecf20Sopenharmony_ci * */ 10628c2ecf20Sopenharmony_cistatic int it8709_get_irq_causes(struct ite_dev *dev) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci u8 iflags; 10658c2ecf20Sopenharmony_ci int ret = 0; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* read the interrupt flags */ 10708c2ecf20Sopenharmony_ci iflags = it8709_rm(dev, IT8709_IIR); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (iflags & IT85_TLDLI) 10738c2ecf20Sopenharmony_ci ret |= ITE_IRQ_TX_FIFO; 10748c2ecf20Sopenharmony_ci if (iflags & IT85_RDAI) 10758c2ecf20Sopenharmony_ci ret |= ITE_IRQ_RX_FIFO; 10768c2ecf20Sopenharmony_ci if (iflags & IT85_RFOI) 10778c2ecf20Sopenharmony_ci ret |= ITE_IRQ_RX_FIFO_OVERRUN; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci return ret; 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci/* set the carrier parameters; to be called with the spinlock held */ 10838c2ecf20Sopenharmony_cistatic void it8709_set_carrier_params(struct ite_dev *dev, bool high_freq, 10848c2ecf20Sopenharmony_ci bool use_demodulator, 10858c2ecf20Sopenharmony_ci u8 carrier_freq_bits, u8 allowance_bits, 10868c2ecf20Sopenharmony_ci u8 pulse_width_bits) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci u8 val; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci val = (it8709_rr(dev, IT85_C0CFR) 10938c2ecf20Sopenharmony_ci &~(IT85_HCFS | IT85_CFQ)) | 10948c2ecf20Sopenharmony_ci carrier_freq_bits; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (high_freq) 10978c2ecf20Sopenharmony_ci val |= IT85_HCFS; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci it8709_wr(dev, val, IT85_C0CFR); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* program the C0RCR register */ 11028c2ecf20Sopenharmony_ci val = it8709_rr(dev, IT85_C0RCR) 11038c2ecf20Sopenharmony_ci & ~(IT85_RXEND | IT85_RXDCR); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (use_demodulator) 11068c2ecf20Sopenharmony_ci val |= IT85_RXEND; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci val |= allowance_bits; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci it8709_wr(dev, val, IT85_C0RCR); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci /* program the C0TCR register */ 11138c2ecf20Sopenharmony_ci val = it8709_rr(dev, IT85_C0TCR) & ~IT85_TXMPW; 11148c2ecf20Sopenharmony_ci val |= pulse_width_bits; 11158c2ecf20Sopenharmony_ci it8709_wr(dev, val, IT85_C0TCR); 11168c2ecf20Sopenharmony_ci} 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock 11198c2ecf20Sopenharmony_ci * held */ 11208c2ecf20Sopenharmony_cistatic int it8709_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci int fifo, read = 0; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci /* read how many bytes are still in the FIFO */ 11278c2ecf20Sopenharmony_ci fifo = it8709_rm(dev, IT8709_RFSR) & IT85_RXFBC; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci while (fifo > 0 && buf_size > 0) { 11308c2ecf20Sopenharmony_ci *(buf++) = it8709_rm(dev, IT8709_FIFO + read); 11318c2ecf20Sopenharmony_ci fifo--; 11328c2ecf20Sopenharmony_ci read++; 11338c2ecf20Sopenharmony_ci buf_size--; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci /* 'clear' the FIFO by setting the writing index to 0; this is 11378c2ecf20Sopenharmony_ci * completely bound to be racy, but we can't help it, since it's a 11388c2ecf20Sopenharmony_ci * limitation of the protocol */ 11398c2ecf20Sopenharmony_ci it8709_wm(dev, 0, IT8709_RFSR); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci return read; 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci/* return how many bytes are still in the FIFO; this will be called 11458c2ecf20Sopenharmony_ci * with the device spinlock NOT HELD while waiting for the TX FIFO to get 11468c2ecf20Sopenharmony_ci * empty; let's expect this won't be a problem */ 11478c2ecf20Sopenharmony_cistatic int it8709_get_tx_used_slots(struct ite_dev *dev) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci return it8709_rr(dev, IT85_C0TFSR) & IT85_TXFBC; 11528c2ecf20Sopenharmony_ci} 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci/* put a byte to the TX fifo; this should be called with the spinlock held */ 11558c2ecf20Sopenharmony_cistatic void it8709_put_tx_byte(struct ite_dev *dev, u8 value) 11568c2ecf20Sopenharmony_ci{ 11578c2ecf20Sopenharmony_ci it8709_wr(dev, value, IT85_C0DR); 11588c2ecf20Sopenharmony_ci} 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci/* idle the receiver so that we won't receive samples until another 11618c2ecf20Sopenharmony_ci pulse is detected; this must be called with the device spinlock held */ 11628c2ecf20Sopenharmony_cistatic void it8709_idle_rx(struct ite_dev *dev) 11638c2ecf20Sopenharmony_ci{ 11648c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci /* disable streaming by clearing RXACT writing it as 1 */ 11678c2ecf20Sopenharmony_ci it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) | IT85_RXACT, 11688c2ecf20Sopenharmony_ci IT85_C0RCR); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci /* clear the FIFO */ 11718c2ecf20Sopenharmony_ci it8709_wr(dev, it8709_rr(dev, IT85_C0MSTCR) | IT85_FIFOCLR, 11728c2ecf20Sopenharmony_ci IT85_C0MSTCR); 11738c2ecf20Sopenharmony_ci} 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci/* disable the receiver; this must be called with the device spinlock held */ 11768c2ecf20Sopenharmony_cistatic void it8709_disable_rx(struct ite_dev *dev) 11778c2ecf20Sopenharmony_ci{ 11788c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci /* disable the receiver interrupts */ 11818c2ecf20Sopenharmony_ci it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & 11828c2ecf20Sopenharmony_ci ~(IT85_RDAIE | IT85_RFOIE), 11838c2ecf20Sopenharmony_ci IT85_C0IER); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci /* disable the receiver */ 11868c2ecf20Sopenharmony_ci it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) & ~IT85_RXEN, 11878c2ecf20Sopenharmony_ci IT85_C0RCR); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci /* clear the FIFO and RXACT (actually RXACT should have been cleared 11908c2ecf20Sopenharmony_ci * in the previous it8709_wr(dev, ) call) */ 11918c2ecf20Sopenharmony_ci it8709_idle_rx(dev); 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci/* enable the receiver; this must be called with the device spinlock held */ 11958c2ecf20Sopenharmony_cistatic void it8709_enable_rx(struct ite_dev *dev) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* enable the receiver by setting RXEN */ 12008c2ecf20Sopenharmony_ci it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) | IT85_RXEN, 12018c2ecf20Sopenharmony_ci IT85_C0RCR); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci /* just prepare it to idle for the next reception */ 12048c2ecf20Sopenharmony_ci it8709_idle_rx(dev); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci /* enable the receiver interrupts and master enable flag */ 12078c2ecf20Sopenharmony_ci it8709_wr(dev, it8709_rr(dev, IT85_C0IER) 12088c2ecf20Sopenharmony_ci |IT85_RDAIE | IT85_RFOIE | IT85_IEC, 12098c2ecf20Sopenharmony_ci IT85_C0IER); 12108c2ecf20Sopenharmony_ci} 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci/* disable the transmitter interrupt; this must be called with the device 12138c2ecf20Sopenharmony_ci * spinlock held */ 12148c2ecf20Sopenharmony_cistatic void it8709_disable_tx_interrupt(struct ite_dev *dev) 12158c2ecf20Sopenharmony_ci{ 12168c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* disable the transmitter interrupts */ 12198c2ecf20Sopenharmony_ci it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & ~IT85_TLDLIE, 12208c2ecf20Sopenharmony_ci IT85_C0IER); 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci/* enable the transmitter interrupt; this must be called with the device 12248c2ecf20Sopenharmony_ci * spinlock held */ 12258c2ecf20Sopenharmony_cistatic void it8709_enable_tx_interrupt(struct ite_dev *dev) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci /* enable the transmitter interrupts and master enable flag */ 12308c2ecf20Sopenharmony_ci it8709_wr(dev, it8709_rr(dev, IT85_C0IER) 12318c2ecf20Sopenharmony_ci |IT85_TLDLIE | IT85_IEC, 12328c2ecf20Sopenharmony_ci IT85_C0IER); 12338c2ecf20Sopenharmony_ci} 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci/* disable the device; this must be called with the device spinlock held */ 12368c2ecf20Sopenharmony_cistatic void it8709_disable(struct ite_dev *dev) 12378c2ecf20Sopenharmony_ci{ 12388c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci /* clear out all interrupt enable flags */ 12418c2ecf20Sopenharmony_ci it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & 12428c2ecf20Sopenharmony_ci ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), 12438c2ecf20Sopenharmony_ci IT85_C0IER); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci /* disable the receiver */ 12468c2ecf20Sopenharmony_ci it8709_disable_rx(dev); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci /* erase the FIFO */ 12498c2ecf20Sopenharmony_ci it8709_wr(dev, IT85_FIFOCLR | it8709_rr(dev, IT85_C0MSTCR), 12508c2ecf20Sopenharmony_ci IT85_C0MSTCR); 12518c2ecf20Sopenharmony_ci} 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci/* initialize the hardware */ 12548c2ecf20Sopenharmony_cistatic void it8709_init_hardware(struct ite_dev *dev) 12558c2ecf20Sopenharmony_ci{ 12568c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci /* disable all the interrupts */ 12598c2ecf20Sopenharmony_ci it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & 12608c2ecf20Sopenharmony_ci ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), 12618c2ecf20Sopenharmony_ci IT85_C0IER); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci /* program the baud rate divisor */ 12648c2ecf20Sopenharmony_ci it8709_wr(dev, ITE_BAUDRATE_DIVISOR & 0xff, IT85_C0BDLR); 12658c2ecf20Sopenharmony_ci it8709_wr(dev, (ITE_BAUDRATE_DIVISOR >> 8) & 0xff, 12668c2ecf20Sopenharmony_ci IT85_C0BDHR); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci /* program the C0MSTCR register defaults */ 12698c2ecf20Sopenharmony_ci it8709_wr(dev, (it8709_rr(dev, IT85_C0MSTCR) & 12708c2ecf20Sopenharmony_ci ~(IT85_ILSEL | IT85_ILE | IT85_FIFOTL 12718c2ecf20Sopenharmony_ci | IT85_FIFOCLR | IT85_RESET)) | IT85_FIFOTL_DEFAULT, 12728c2ecf20Sopenharmony_ci IT85_C0MSTCR); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci /* program the C0RCR register defaults */ 12758c2ecf20Sopenharmony_ci it8709_wr(dev, (it8709_rr(dev, IT85_C0RCR) & 12768c2ecf20Sopenharmony_ci ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND | IT85_RXACT 12778c2ecf20Sopenharmony_ci | IT85_RXDCR)) | ITE_RXDCR_DEFAULT, 12788c2ecf20Sopenharmony_ci IT85_C0RCR); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci /* program the C0TCR register defaults */ 12818c2ecf20Sopenharmony_ci it8709_wr(dev, (it8709_rr(dev, IT85_C0TCR) & ~(IT85_TXMPM | IT85_TXMPW)) 12828c2ecf20Sopenharmony_ci | IT85_TXRLE | IT85_TXENDF | IT85_TXMPM_DEFAULT 12838c2ecf20Sopenharmony_ci | IT85_TXMPW_DEFAULT, 12848c2ecf20Sopenharmony_ci IT85_C0TCR); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci /* program the carrier parameters */ 12878c2ecf20Sopenharmony_ci ite_set_carrier_params(dev); 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci/* generic hardware setup/teardown code */ 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci/* activate the device for use */ 12948c2ecf20Sopenharmony_cistatic int ite_open(struct rc_dev *rcdev) 12958c2ecf20Sopenharmony_ci{ 12968c2ecf20Sopenharmony_ci struct ite_dev *dev = rcdev->priv; 12978c2ecf20Sopenharmony_ci unsigned long flags; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 13028c2ecf20Sopenharmony_ci dev->in_use = true; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci /* enable the receiver */ 13058c2ecf20Sopenharmony_ci dev->params.enable_rx(dev); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci return 0; 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci/* deactivate the device for use */ 13138c2ecf20Sopenharmony_cistatic void ite_close(struct rc_dev *rcdev) 13148c2ecf20Sopenharmony_ci{ 13158c2ecf20Sopenharmony_ci struct ite_dev *dev = rcdev->priv; 13168c2ecf20Sopenharmony_ci unsigned long flags; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 13218c2ecf20Sopenharmony_ci dev->in_use = false; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* wait for any transmission to end */ 13248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 13258c2ecf20Sopenharmony_ci wait_event_interruptible(dev->tx_ended, !dev->transmitting); 13268c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci dev->params.disable(dev); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 13318c2ecf20Sopenharmony_ci} 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci/* supported models and their parameters */ 13348c2ecf20Sopenharmony_cistatic const struct ite_dev_params ite_dev_descs[] = { 13358c2ecf20Sopenharmony_ci { /* 0: ITE8704 */ 13368c2ecf20Sopenharmony_ci .model = "ITE8704 CIR transceiver", 13378c2ecf20Sopenharmony_ci .io_region_size = IT87_IOREG_LENGTH, 13388c2ecf20Sopenharmony_ci .io_rsrc_no = 0, 13398c2ecf20Sopenharmony_ci .hw_tx_capable = true, 13408c2ecf20Sopenharmony_ci .sample_period = (u32) (1000000000ULL / 115200), 13418c2ecf20Sopenharmony_ci .tx_carrier_freq = 38000, 13428c2ecf20Sopenharmony_ci .tx_duty_cycle = 33, 13438c2ecf20Sopenharmony_ci .rx_low_carrier_freq = 0, 13448c2ecf20Sopenharmony_ci .rx_high_carrier_freq = 0, 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci /* operations */ 13478c2ecf20Sopenharmony_ci .get_irq_causes = it87_get_irq_causes, 13488c2ecf20Sopenharmony_ci .enable_rx = it87_enable_rx, 13498c2ecf20Sopenharmony_ci .idle_rx = it87_idle_rx, 13508c2ecf20Sopenharmony_ci .disable_rx = it87_idle_rx, 13518c2ecf20Sopenharmony_ci .get_rx_bytes = it87_get_rx_bytes, 13528c2ecf20Sopenharmony_ci .enable_tx_interrupt = it87_enable_tx_interrupt, 13538c2ecf20Sopenharmony_ci .disable_tx_interrupt = it87_disable_tx_interrupt, 13548c2ecf20Sopenharmony_ci .get_tx_used_slots = it87_get_tx_used_slots, 13558c2ecf20Sopenharmony_ci .put_tx_byte = it87_put_tx_byte, 13568c2ecf20Sopenharmony_ci .disable = it87_disable, 13578c2ecf20Sopenharmony_ci .init_hardware = it87_init_hardware, 13588c2ecf20Sopenharmony_ci .set_carrier_params = it87_set_carrier_params, 13598c2ecf20Sopenharmony_ci }, 13608c2ecf20Sopenharmony_ci { /* 1: ITE8713 */ 13618c2ecf20Sopenharmony_ci .model = "ITE8713 CIR transceiver", 13628c2ecf20Sopenharmony_ci .io_region_size = IT87_IOREG_LENGTH, 13638c2ecf20Sopenharmony_ci .io_rsrc_no = 0, 13648c2ecf20Sopenharmony_ci .hw_tx_capable = true, 13658c2ecf20Sopenharmony_ci .sample_period = (u32) (1000000000ULL / 115200), 13668c2ecf20Sopenharmony_ci .tx_carrier_freq = 38000, 13678c2ecf20Sopenharmony_ci .tx_duty_cycle = 33, 13688c2ecf20Sopenharmony_ci .rx_low_carrier_freq = 0, 13698c2ecf20Sopenharmony_ci .rx_high_carrier_freq = 0, 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci /* operations */ 13728c2ecf20Sopenharmony_ci .get_irq_causes = it87_get_irq_causes, 13738c2ecf20Sopenharmony_ci .enable_rx = it87_enable_rx, 13748c2ecf20Sopenharmony_ci .idle_rx = it87_idle_rx, 13758c2ecf20Sopenharmony_ci .disable_rx = it87_idle_rx, 13768c2ecf20Sopenharmony_ci .get_rx_bytes = it87_get_rx_bytes, 13778c2ecf20Sopenharmony_ci .enable_tx_interrupt = it87_enable_tx_interrupt, 13788c2ecf20Sopenharmony_ci .disable_tx_interrupt = it87_disable_tx_interrupt, 13798c2ecf20Sopenharmony_ci .get_tx_used_slots = it87_get_tx_used_slots, 13808c2ecf20Sopenharmony_ci .put_tx_byte = it87_put_tx_byte, 13818c2ecf20Sopenharmony_ci .disable = it87_disable, 13828c2ecf20Sopenharmony_ci .init_hardware = it87_init_hardware, 13838c2ecf20Sopenharmony_ci .set_carrier_params = it87_set_carrier_params, 13848c2ecf20Sopenharmony_ci }, 13858c2ecf20Sopenharmony_ci { /* 2: ITE8708 */ 13868c2ecf20Sopenharmony_ci .model = "ITE8708 CIR transceiver", 13878c2ecf20Sopenharmony_ci .io_region_size = IT8708_IOREG_LENGTH, 13888c2ecf20Sopenharmony_ci .io_rsrc_no = 0, 13898c2ecf20Sopenharmony_ci .hw_tx_capable = true, 13908c2ecf20Sopenharmony_ci .sample_period = (u32) (1000000000ULL / 115200), 13918c2ecf20Sopenharmony_ci .tx_carrier_freq = 38000, 13928c2ecf20Sopenharmony_ci .tx_duty_cycle = 33, 13938c2ecf20Sopenharmony_ci .rx_low_carrier_freq = 0, 13948c2ecf20Sopenharmony_ci .rx_high_carrier_freq = 0, 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci /* operations */ 13978c2ecf20Sopenharmony_ci .get_irq_causes = it8708_get_irq_causes, 13988c2ecf20Sopenharmony_ci .enable_rx = it8708_enable_rx, 13998c2ecf20Sopenharmony_ci .idle_rx = it8708_idle_rx, 14008c2ecf20Sopenharmony_ci .disable_rx = it8708_idle_rx, 14018c2ecf20Sopenharmony_ci .get_rx_bytes = it8708_get_rx_bytes, 14028c2ecf20Sopenharmony_ci .enable_tx_interrupt = it8708_enable_tx_interrupt, 14038c2ecf20Sopenharmony_ci .disable_tx_interrupt = 14048c2ecf20Sopenharmony_ci it8708_disable_tx_interrupt, 14058c2ecf20Sopenharmony_ci .get_tx_used_slots = it8708_get_tx_used_slots, 14068c2ecf20Sopenharmony_ci .put_tx_byte = it8708_put_tx_byte, 14078c2ecf20Sopenharmony_ci .disable = it8708_disable, 14088c2ecf20Sopenharmony_ci .init_hardware = it8708_init_hardware, 14098c2ecf20Sopenharmony_ci .set_carrier_params = it8708_set_carrier_params, 14108c2ecf20Sopenharmony_ci }, 14118c2ecf20Sopenharmony_ci { /* 3: ITE8709 */ 14128c2ecf20Sopenharmony_ci .model = "ITE8709 CIR transceiver", 14138c2ecf20Sopenharmony_ci .io_region_size = IT8709_IOREG_LENGTH, 14148c2ecf20Sopenharmony_ci .io_rsrc_no = 2, 14158c2ecf20Sopenharmony_ci .hw_tx_capable = true, 14168c2ecf20Sopenharmony_ci .sample_period = (u32) (1000000000ULL / 115200), 14178c2ecf20Sopenharmony_ci .tx_carrier_freq = 38000, 14188c2ecf20Sopenharmony_ci .tx_duty_cycle = 33, 14198c2ecf20Sopenharmony_ci .rx_low_carrier_freq = 0, 14208c2ecf20Sopenharmony_ci .rx_high_carrier_freq = 0, 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci /* operations */ 14238c2ecf20Sopenharmony_ci .get_irq_causes = it8709_get_irq_causes, 14248c2ecf20Sopenharmony_ci .enable_rx = it8709_enable_rx, 14258c2ecf20Sopenharmony_ci .idle_rx = it8709_idle_rx, 14268c2ecf20Sopenharmony_ci .disable_rx = it8709_idle_rx, 14278c2ecf20Sopenharmony_ci .get_rx_bytes = it8709_get_rx_bytes, 14288c2ecf20Sopenharmony_ci .enable_tx_interrupt = it8709_enable_tx_interrupt, 14298c2ecf20Sopenharmony_ci .disable_tx_interrupt = 14308c2ecf20Sopenharmony_ci it8709_disable_tx_interrupt, 14318c2ecf20Sopenharmony_ci .get_tx_used_slots = it8709_get_tx_used_slots, 14328c2ecf20Sopenharmony_ci .put_tx_byte = it8709_put_tx_byte, 14338c2ecf20Sopenharmony_ci .disable = it8709_disable, 14348c2ecf20Sopenharmony_ci .init_hardware = it8709_init_hardware, 14358c2ecf20Sopenharmony_ci .set_carrier_params = it8709_set_carrier_params, 14368c2ecf20Sopenharmony_ci }, 14378c2ecf20Sopenharmony_ci}; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic const struct pnp_device_id ite_ids[] = { 14408c2ecf20Sopenharmony_ci {"ITE8704", 0}, /* Default model */ 14418c2ecf20Sopenharmony_ci {"ITE8713", 1}, /* CIR found in EEEBox 1501U */ 14428c2ecf20Sopenharmony_ci {"ITE8708", 2}, /* Bridged IT8512 */ 14438c2ecf20Sopenharmony_ci {"ITE8709", 3}, /* SRAM-Bridged IT8512 */ 14448c2ecf20Sopenharmony_ci {"", 0}, 14458c2ecf20Sopenharmony_ci}; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci/* allocate memory, probe hardware, and initialize everything */ 14488c2ecf20Sopenharmony_cistatic int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id 14498c2ecf20Sopenharmony_ci *dev_id) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci const struct ite_dev_params *dev_desc = NULL; 14528c2ecf20Sopenharmony_ci struct ite_dev *itdev = NULL; 14538c2ecf20Sopenharmony_ci struct rc_dev *rdev = NULL; 14548c2ecf20Sopenharmony_ci int ret = -ENOMEM; 14558c2ecf20Sopenharmony_ci int model_no; 14568c2ecf20Sopenharmony_ci int io_rsrc_no; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci itdev = kzalloc(sizeof(struct ite_dev), GFP_KERNEL); 14618c2ecf20Sopenharmony_ci if (!itdev) 14628c2ecf20Sopenharmony_ci return ret; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci /* input device for IR remote (and tx) */ 14658c2ecf20Sopenharmony_ci rdev = rc_allocate_device(RC_DRIVER_IR_RAW); 14668c2ecf20Sopenharmony_ci if (!rdev) 14678c2ecf20Sopenharmony_ci goto exit_free_dev_rdev; 14688c2ecf20Sopenharmony_ci itdev->rdev = rdev; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci ret = -ENODEV; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci /* get the model number */ 14738c2ecf20Sopenharmony_ci model_no = (int)dev_id->driver_data; 14748c2ecf20Sopenharmony_ci ite_pr(KERN_NOTICE, "Auto-detected model: %s\n", 14758c2ecf20Sopenharmony_ci ite_dev_descs[model_no].model); 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci if (model_number >= 0 && model_number < ARRAY_SIZE(ite_dev_descs)) { 14788c2ecf20Sopenharmony_ci model_no = model_number; 14798c2ecf20Sopenharmony_ci ite_pr(KERN_NOTICE, "The model has been fixed by a module parameter."); 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci ite_pr(KERN_NOTICE, "Using model: %s\n", ite_dev_descs[model_no].model); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci /* get the description for the device */ 14858c2ecf20Sopenharmony_ci dev_desc = &ite_dev_descs[model_no]; 14868c2ecf20Sopenharmony_ci io_rsrc_no = dev_desc->io_rsrc_no; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci /* validate pnp resources */ 14898c2ecf20Sopenharmony_ci if (!pnp_port_valid(pdev, io_rsrc_no) || 14908c2ecf20Sopenharmony_ci pnp_port_len(pdev, io_rsrc_no) != dev_desc->io_region_size) { 14918c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "IR PNP Port not valid!\n"); 14928c2ecf20Sopenharmony_ci goto exit_free_dev_rdev; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci if (!pnp_irq_valid(pdev, 0)) { 14968c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "PNP IRQ not valid!\n"); 14978c2ecf20Sopenharmony_ci goto exit_free_dev_rdev; 14988c2ecf20Sopenharmony_ci } 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci /* store resource values */ 15018c2ecf20Sopenharmony_ci itdev->cir_addr = pnp_port_start(pdev, io_rsrc_no); 15028c2ecf20Sopenharmony_ci itdev->cir_irq = pnp_irq(pdev, 0); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci /* initialize spinlocks */ 15058c2ecf20Sopenharmony_ci spin_lock_init(&itdev->lock); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci /* set driver data into the pnp device */ 15088c2ecf20Sopenharmony_ci pnp_set_drvdata(pdev, itdev); 15098c2ecf20Sopenharmony_ci itdev->pdev = pdev; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci /* initialize waitqueues for transmission */ 15128c2ecf20Sopenharmony_ci init_waitqueue_head(&itdev->tx_queue); 15138c2ecf20Sopenharmony_ci init_waitqueue_head(&itdev->tx_ended); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci /* copy model-specific parameters */ 15168c2ecf20Sopenharmony_ci itdev->params = *dev_desc; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci /* apply any overrides */ 15198c2ecf20Sopenharmony_ci if (sample_period > 0) 15208c2ecf20Sopenharmony_ci itdev->params.sample_period = sample_period; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (tx_carrier_freq > 0) 15238c2ecf20Sopenharmony_ci itdev->params.tx_carrier_freq = tx_carrier_freq; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (tx_duty_cycle > 0 && tx_duty_cycle <= 100) 15268c2ecf20Sopenharmony_ci itdev->params.tx_duty_cycle = tx_duty_cycle; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci if (rx_low_carrier_freq > 0) 15298c2ecf20Sopenharmony_ci itdev->params.rx_low_carrier_freq = rx_low_carrier_freq; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci if (rx_high_carrier_freq > 0) 15328c2ecf20Sopenharmony_ci itdev->params.rx_high_carrier_freq = rx_high_carrier_freq; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci /* print out parameters */ 15358c2ecf20Sopenharmony_ci ite_pr(KERN_NOTICE, "TX-capable: %d\n", (int) 15368c2ecf20Sopenharmony_ci itdev->params.hw_tx_capable); 15378c2ecf20Sopenharmony_ci ite_pr(KERN_NOTICE, "Sample period (ns): %ld\n", (long) 15388c2ecf20Sopenharmony_ci itdev->params.sample_period); 15398c2ecf20Sopenharmony_ci ite_pr(KERN_NOTICE, "TX carrier frequency (Hz): %d\n", (int) 15408c2ecf20Sopenharmony_ci itdev->params.tx_carrier_freq); 15418c2ecf20Sopenharmony_ci ite_pr(KERN_NOTICE, "TX duty cycle (%%): %d\n", (int) 15428c2ecf20Sopenharmony_ci itdev->params.tx_duty_cycle); 15438c2ecf20Sopenharmony_ci ite_pr(KERN_NOTICE, "RX low carrier frequency (Hz): %d\n", (int) 15448c2ecf20Sopenharmony_ci itdev->params.rx_low_carrier_freq); 15458c2ecf20Sopenharmony_ci ite_pr(KERN_NOTICE, "RX high carrier frequency (Hz): %d\n", (int) 15468c2ecf20Sopenharmony_ci itdev->params.rx_high_carrier_freq); 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci /* set up hardware initial state */ 15498c2ecf20Sopenharmony_ci itdev->params.init_hardware(itdev); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci /* set up ir-core props */ 15528c2ecf20Sopenharmony_ci rdev->priv = itdev; 15538c2ecf20Sopenharmony_ci rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; 15548c2ecf20Sopenharmony_ci rdev->open = ite_open; 15558c2ecf20Sopenharmony_ci rdev->close = ite_close; 15568c2ecf20Sopenharmony_ci rdev->s_idle = ite_s_idle; 15578c2ecf20Sopenharmony_ci rdev->s_rx_carrier_range = ite_set_rx_carrier_range; 15588c2ecf20Sopenharmony_ci /* FIFO threshold is 17 bytes, so 17 * 8 samples minimum */ 15598c2ecf20Sopenharmony_ci rdev->min_timeout = 17 * 8 * ITE_BAUDRATE_DIVISOR * 15608c2ecf20Sopenharmony_ci itdev->params.sample_period / 1000; 15618c2ecf20Sopenharmony_ci rdev->timeout = IR_DEFAULT_TIMEOUT; 15628c2ecf20Sopenharmony_ci rdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; 15638c2ecf20Sopenharmony_ci rdev->rx_resolution = ITE_BAUDRATE_DIVISOR * 15648c2ecf20Sopenharmony_ci itdev->params.sample_period / 1000; 15658c2ecf20Sopenharmony_ci rdev->tx_resolution = ITE_BAUDRATE_DIVISOR * 15668c2ecf20Sopenharmony_ci itdev->params.sample_period / 1000; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci /* set up transmitter related values if needed */ 15698c2ecf20Sopenharmony_ci if (itdev->params.hw_tx_capable) { 15708c2ecf20Sopenharmony_ci rdev->tx_ir = ite_tx_ir; 15718c2ecf20Sopenharmony_ci rdev->s_tx_carrier = ite_set_tx_carrier; 15728c2ecf20Sopenharmony_ci rdev->s_tx_duty_cycle = ite_set_tx_duty_cycle; 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci rdev->device_name = dev_desc->model; 15768c2ecf20Sopenharmony_ci rdev->input_id.bustype = BUS_HOST; 15778c2ecf20Sopenharmony_ci rdev->input_id.vendor = PCI_VENDOR_ID_ITE; 15788c2ecf20Sopenharmony_ci rdev->input_id.product = 0; 15798c2ecf20Sopenharmony_ci rdev->input_id.version = 0; 15808c2ecf20Sopenharmony_ci rdev->driver_name = ITE_DRIVER_NAME; 15818c2ecf20Sopenharmony_ci rdev->map_name = RC_MAP_RC6_MCE; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci ret = rc_register_device(rdev); 15848c2ecf20Sopenharmony_ci if (ret) 15858c2ecf20Sopenharmony_ci goto exit_free_dev_rdev; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci ret = -EBUSY; 15888c2ecf20Sopenharmony_ci /* now claim resources */ 15898c2ecf20Sopenharmony_ci if (!request_region(itdev->cir_addr, 15908c2ecf20Sopenharmony_ci dev_desc->io_region_size, ITE_DRIVER_NAME)) 15918c2ecf20Sopenharmony_ci goto exit_unregister_device; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (request_irq(itdev->cir_irq, ite_cir_isr, IRQF_SHARED, 15948c2ecf20Sopenharmony_ci ITE_DRIVER_NAME, (void *)itdev)) 15958c2ecf20Sopenharmony_ci goto exit_release_cir_addr; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci ite_pr(KERN_NOTICE, "driver has been successfully loaded\n"); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci return 0; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ciexit_release_cir_addr: 16028c2ecf20Sopenharmony_ci release_region(itdev->cir_addr, itdev->params.io_region_size); 16038c2ecf20Sopenharmony_ciexit_unregister_device: 16048c2ecf20Sopenharmony_ci rc_unregister_device(rdev); 16058c2ecf20Sopenharmony_ci rdev = NULL; 16068c2ecf20Sopenharmony_ciexit_free_dev_rdev: 16078c2ecf20Sopenharmony_ci rc_free_device(rdev); 16088c2ecf20Sopenharmony_ci kfree(itdev); 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci return ret; 16118c2ecf20Sopenharmony_ci} 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_cistatic void ite_remove(struct pnp_dev *pdev) 16148c2ecf20Sopenharmony_ci{ 16158c2ecf20Sopenharmony_ci struct ite_dev *dev = pnp_get_drvdata(pdev); 16168c2ecf20Sopenharmony_ci unsigned long flags; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci /* disable hardware */ 16238c2ecf20Sopenharmony_ci dev->params.disable(dev); 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci /* free resources */ 16288c2ecf20Sopenharmony_ci free_irq(dev->cir_irq, dev); 16298c2ecf20Sopenharmony_ci release_region(dev->cir_addr, dev->params.io_region_size); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci rc_unregister_device(dev->rdev); 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci kfree(dev); 16348c2ecf20Sopenharmony_ci} 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_cistatic int ite_suspend(struct pnp_dev *pdev, pm_message_t state) 16378c2ecf20Sopenharmony_ci{ 16388c2ecf20Sopenharmony_ci struct ite_dev *dev = pnp_get_drvdata(pdev); 16398c2ecf20Sopenharmony_ci unsigned long flags; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci /* wait for any transmission to end */ 16448c2ecf20Sopenharmony_ci wait_event_interruptible(dev->tx_ended, !dev->transmitting); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci /* disable all interrupts */ 16498c2ecf20Sopenharmony_ci dev->params.disable(dev); 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci return 0; 16548c2ecf20Sopenharmony_ci} 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_cistatic int ite_resume(struct pnp_dev *pdev) 16578c2ecf20Sopenharmony_ci{ 16588c2ecf20Sopenharmony_ci struct ite_dev *dev = pnp_get_drvdata(pdev); 16598c2ecf20Sopenharmony_ci unsigned long flags; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci /* reinitialize hardware config registers */ 16668c2ecf20Sopenharmony_ci dev->params.init_hardware(dev); 16678c2ecf20Sopenharmony_ci /* enable the receiver */ 16688c2ecf20Sopenharmony_ci dev->params.enable_rx(dev); 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci return 0; 16738c2ecf20Sopenharmony_ci} 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_cistatic void ite_shutdown(struct pnp_dev *pdev) 16768c2ecf20Sopenharmony_ci{ 16778c2ecf20Sopenharmony_ci struct ite_dev *dev = pnp_get_drvdata(pdev); 16788c2ecf20Sopenharmony_ci unsigned long flags; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci ite_dbg("%s called", __func__); 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci /* disable all interrupts */ 16858c2ecf20Sopenharmony_ci dev->params.disable(dev); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 16888c2ecf20Sopenharmony_ci} 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_cistatic struct pnp_driver ite_driver = { 16918c2ecf20Sopenharmony_ci .name = ITE_DRIVER_NAME, 16928c2ecf20Sopenharmony_ci .id_table = ite_ids, 16938c2ecf20Sopenharmony_ci .probe = ite_probe, 16948c2ecf20Sopenharmony_ci .remove = ite_remove, 16958c2ecf20Sopenharmony_ci .suspend = ite_suspend, 16968c2ecf20Sopenharmony_ci .resume = ite_resume, 16978c2ecf20Sopenharmony_ci .shutdown = ite_shutdown, 16988c2ecf20Sopenharmony_ci}; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pnp, ite_ids); 17018c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ITE Tech Inc. IT8712F/ITE8512F CIR driver"); 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ciMODULE_AUTHOR("Juan J. Garcia de Soria <skandalfo@gmail.com>"); 17048c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_cimodule_pnp_driver(ite_driver); 1707