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