brintos

brintos / linux-shallow public Read only

0
0
Text · 9.1 KiB · fded2c2 Raw
389 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * meson-ir-tx.c - Amlogic Meson IR TX driver4 *5 * Copyright (c) 2021, SberDevices. All Rights Reserved.6 *7 * Author: Viktor Prutyanov <viktor.prutyanov@phystech.edu>8 */9 10#include <linux/device.h>11#include <linux/module.h>12#include <linux/sched.h>13#include <linux/platform_device.h>14#include <linux/of.h>15#include <linux/interrupt.h>16#include <linux/spinlock.h>17#include <linux/of_irq.h>18#include <linux/clk.h>19#include <linux/slab.h>20#include <media/rc-core.h>21 22#define DEVICE_NAME	"Meson IR TX"23#define DRIVER_NAME	"meson-ir-tx"24 25#define MIRTX_DEFAULT_CARRIER		3800026#define MIRTX_DEFAULT_DUTY_CYCLE	5027#define MIRTX_FIFO_THD			3228 29#define IRB_MOD_1US_CLK_RATE	100000030 31#define IRB_FIFO_LEN	12832 33#define IRB_ADDR0	0x034#define IRB_ADDR1	0x435#define IRB_ADDR2	0x836#define IRB_ADDR3	0xc37 38#define IRB_MAX_DELAY	(1 << 10)39#define IRB_DELAY_MASK	(IRB_MAX_DELAY - 1)40 41/* IRCTRL_IR_BLASTER_ADDR0 */42#define IRB_MOD_CLK(x)		((x) << 12)43#define IRB_MOD_SYS_CLK		044#define IRB_MOD_XTAL3_CLK	145#define IRB_MOD_1US_CLK		246#define IRB_MOD_10US_CLK	347#define IRB_INIT_HIGH		BIT(2)48#define IRB_ENABLE		BIT(0)49 50/* IRCTRL_IR_BLASTER_ADDR2 */51#define IRB_MOD_COUNT(lo, hi)	((((lo) - 1) << 16) | ((hi) - 1))52 53/* IRCTRL_IR_BLASTER_ADDR2 */54#define IRB_WRITE_FIFO	BIT(16)55#define IRB_MOD_ENABLE	BIT(12)56#define IRB_TB_1US	(0x0 << 10)57#define IRB_TB_10US	(0x1 << 10)58#define IRB_TB_100US	(0x2 << 10)59#define IRB_TB_MOD_CLK	(0x3 << 10)60 61/* IRCTRL_IR_BLASTER_ADDR3 */62#define IRB_FIFO_THD_PENDING	BIT(16)63#define IRB_FIFO_IRQ_ENABLE	BIT(8)64 65struct meson_irtx {66	struct device *dev;67	void __iomem *reg_base;68	u32 *buf;69	unsigned int buf_len;70	unsigned int buf_head;71	unsigned int carrier;72	unsigned int duty_cycle;73	/* Locks buf */74	spinlock_t lock;75	struct completion completion;76	unsigned long clk_rate;77};78 79static void meson_irtx_set_mod(struct meson_irtx *ir)80{81	unsigned int cnt = DIV_ROUND_CLOSEST(ir->clk_rate, ir->carrier);82	unsigned int pulse_cnt = DIV_ROUND_CLOSEST(cnt * ir->duty_cycle, 100);83	unsigned int space_cnt = cnt - pulse_cnt;84 85	dev_dbg(ir->dev, "F_mod = %uHz, T_mod = %luns, duty_cycle = %u%%\n",86		ir->carrier, NSEC_PER_SEC / ir->clk_rate * cnt,87		100 * pulse_cnt / cnt);88 89	writel(IRB_MOD_COUNT(pulse_cnt, space_cnt),90	       ir->reg_base + IRB_ADDR1);91}92 93static void meson_irtx_setup(struct meson_irtx *ir, unsigned int clk_nr)94{95	/*96	 * Disable the TX, set modulator clock tick and set initialize97	 * output to be high. Set up carrier frequency and duty cycle. Then98	 * unset initialize output. Enable FIFO interrupt, set FIFO interrupt99	 * threshold. Finally, enable the transmitter back.100	 */101	writel(~IRB_ENABLE & (IRB_MOD_CLK(clk_nr) | IRB_INIT_HIGH),102	       ir->reg_base + IRB_ADDR0);103	meson_irtx_set_mod(ir);104	writel(readl(ir->reg_base + IRB_ADDR0) & ~IRB_INIT_HIGH,105	       ir->reg_base + IRB_ADDR0);106	writel(IRB_FIFO_IRQ_ENABLE | MIRTX_FIFO_THD,107	       ir->reg_base + IRB_ADDR3);108	writel(readl(ir->reg_base + IRB_ADDR0) | IRB_ENABLE,109	       ir->reg_base + IRB_ADDR0);110}111 112static u32 meson_irtx_prepare_pulse(struct meson_irtx *ir, unsigned int time)113{114	unsigned int delay;115	unsigned int tb = IRB_TB_MOD_CLK;116	unsigned int tb_us = DIV_ROUND_CLOSEST(USEC_PER_SEC, ir->carrier);117 118	delay = (DIV_ROUND_CLOSEST(time, tb_us) - 1) & IRB_DELAY_MASK;119 120	return ((IRB_WRITE_FIFO | IRB_MOD_ENABLE) | tb | delay);121}122 123static u32 meson_irtx_prepare_space(struct meson_irtx *ir, unsigned int time)124{125	unsigned int delay;126	unsigned int tb = IRB_TB_100US;127	unsigned int tb_us = 100;128 129	if (time <= IRB_MAX_DELAY) {130		tb = IRB_TB_1US;131		tb_us = 1;132	} else if (time <= 10 * IRB_MAX_DELAY) {133		tb = IRB_TB_10US;134		tb_us = 10;135	} else if (time <= 100 * IRB_MAX_DELAY) {136		tb = IRB_TB_100US;137		tb_us = 100;138	}139 140	delay = (DIV_ROUND_CLOSEST(time, tb_us) - 1) & IRB_DELAY_MASK;141 142	return ((IRB_WRITE_FIFO & ~IRB_MOD_ENABLE) | tb | delay);143}144 145static void meson_irtx_send_buffer(struct meson_irtx *ir)146{147	unsigned int nr = 0;148	unsigned int max_fifo_level = IRB_FIFO_LEN - MIRTX_FIFO_THD;149 150	while (ir->buf_head < ir->buf_len && nr < max_fifo_level) {151		writel(ir->buf[ir->buf_head], ir->reg_base + IRB_ADDR2);152 153		ir->buf_head++;154		nr++;155	}156}157 158static bool meson_irtx_check_buf(struct meson_irtx *ir,159				 unsigned int *buf, unsigned int len)160{161	unsigned int i;162 163	for (i = 0; i < len; i++) {164		unsigned int max_tb_us;165		/*166		 * Max space timebase is 100 us.167		 * Pulse timebase equals to carrier period.168		 */169		if (i % 2 == 0)170			max_tb_us = USEC_PER_SEC / ir->carrier;171		else172			max_tb_us = 100;173 174		if (buf[i] >= max_tb_us * IRB_MAX_DELAY)175			return false;176	}177 178	return true;179}180 181static void meson_irtx_fill_buf(struct meson_irtx *ir, u32 *dst_buf,182				unsigned int *src_buf, unsigned int len)183{184	unsigned int i;185 186	for (i = 0; i < len; i++) {187		if (i % 2 == 0)188			dst_buf[i] = meson_irtx_prepare_pulse(ir, src_buf[i]);189		else190			dst_buf[i] = meson_irtx_prepare_space(ir, src_buf[i]);191	}192}193 194static irqreturn_t meson_irtx_irqhandler(int irq, void *data)195{196	unsigned long flags;197	struct meson_irtx *ir = data;198 199	writel(readl(ir->reg_base + IRB_ADDR3) & ~IRB_FIFO_THD_PENDING,200	       ir->reg_base + IRB_ADDR3);201 202	if (completion_done(&ir->completion))203		return IRQ_HANDLED;204 205	spin_lock_irqsave(&ir->lock, flags);206	if (ir->buf_head < ir->buf_len)207		meson_irtx_send_buffer(ir);208	else209		complete(&ir->completion);210	spin_unlock_irqrestore(&ir->lock, flags);211 212	return IRQ_HANDLED;213}214 215static int meson_irtx_set_carrier(struct rc_dev *rc, u32 carrier)216{217	struct meson_irtx *ir = rc->priv;218 219	if (carrier == 0)220		return -EINVAL;221 222	ir->carrier = carrier;223	meson_irtx_set_mod(ir);224 225	return 0;226}227 228static int meson_irtx_set_duty_cycle(struct rc_dev *rc, u32 duty_cycle)229{230	struct meson_irtx *ir = rc->priv;231 232	ir->duty_cycle = duty_cycle;233	meson_irtx_set_mod(ir);234 235	return 0;236}237 238static void meson_irtx_update_buf(struct meson_irtx *ir, u32 *buf,239				  unsigned int len, unsigned int head)240{241	ir->buf = buf;242	ir->buf_len = len;243	ir->buf_head = head;244}245 246static int meson_irtx_transmit(struct rc_dev *rc, unsigned int *buf,247			       unsigned int len)248{249	unsigned long flags;250	struct meson_irtx *ir = rc->priv;251	u32 *tx_buf;252	int ret = len;253 254	if (!meson_irtx_check_buf(ir, buf, len))255		return -EINVAL;256 257	tx_buf = kmalloc_array(len, sizeof(u32), GFP_KERNEL);258	if (!tx_buf)259		return -ENOMEM;260 261	meson_irtx_fill_buf(ir, tx_buf, buf, len);262	dev_dbg(ir->dev, "TX buffer filled, length = %u\n", len);263 264	spin_lock_irqsave(&ir->lock, flags);265	meson_irtx_update_buf(ir, tx_buf, len, 0);266	reinit_completion(&ir->completion);267	meson_irtx_send_buffer(ir);268	spin_unlock_irqrestore(&ir->lock, flags);269 270	if (!wait_for_completion_timeout(&ir->completion,271					 usecs_to_jiffies(IR_MAX_DURATION)))272		ret = -ETIMEDOUT;273 274	spin_lock_irqsave(&ir->lock, flags);275	kfree(ir->buf);276	meson_irtx_update_buf(ir, NULL, 0, 0);277	spin_unlock_irqrestore(&ir->lock, flags);278 279	return ret;280}281 282static int meson_irtx_mod_clock_probe(struct meson_irtx *ir,283				      unsigned int *clk_nr)284{285	struct device_node *np = ir->dev->of_node;286	struct clk *clock;287 288	if (!np)289		return -ENODEV;290 291	clock = devm_clk_get(ir->dev, "xtal");292	if (IS_ERR(clock) || clk_prepare_enable(clock))293		return -ENODEV;294 295	*clk_nr = IRB_MOD_XTAL3_CLK;296	ir->clk_rate = clk_get_rate(clock) / 3;297 298	if (ir->clk_rate < IRB_MOD_1US_CLK_RATE) {299		*clk_nr = IRB_MOD_1US_CLK;300		ir->clk_rate = IRB_MOD_1US_CLK_RATE;301	}302 303	dev_info(ir->dev, "F_clk = %luHz\n", ir->clk_rate);304 305	return 0;306}307 308static int meson_irtx_probe(struct platform_device *pdev)309{310	struct device *dev = &pdev->dev;311	struct meson_irtx *ir;312	struct rc_dev *rc;313	int irq;314	unsigned int clk_nr;315	int ret;316 317	ir = devm_kzalloc(dev, sizeof(*ir), GFP_KERNEL);318	if (!ir)319		return -ENOMEM;320 321	ir->reg_base = devm_platform_ioremap_resource(pdev, 0);322	if (IS_ERR(ir->reg_base))323		return PTR_ERR(ir->reg_base);324 325	irq = platform_get_irq(pdev, 0);326	if (irq < 0)327		return -ENODEV;328 329	ir->dev = dev;330	ir->carrier = MIRTX_DEFAULT_CARRIER;331	ir->duty_cycle = MIRTX_DEFAULT_DUTY_CYCLE;332	init_completion(&ir->completion);333	spin_lock_init(&ir->lock);334 335	ret = meson_irtx_mod_clock_probe(ir, &clk_nr);336	if (ret)337		return dev_err_probe(dev, ret, "modulator clock setup failed\n");338 339	meson_irtx_setup(ir, clk_nr);340 341	ret = devm_request_irq(dev, irq,342			       meson_irtx_irqhandler,343			       IRQF_TRIGGER_RISING,344			       DRIVER_NAME, ir);345	if (ret)346		return dev_err_probe(dev, ret, "irq request failed\n");347 348	rc = rc_allocate_device(RC_DRIVER_IR_RAW_TX);349	if (!rc)350		return -ENOMEM;351 352	rc->driver_name = DRIVER_NAME;353	rc->device_name = DEVICE_NAME;354	rc->priv = ir;355 356	rc->tx_ir = meson_irtx_transmit;357	rc->s_tx_carrier = meson_irtx_set_carrier;358	rc->s_tx_duty_cycle = meson_irtx_set_duty_cycle;359 360	ret = devm_rc_register_device(dev, rc);361	if (ret < 0) {362		rc_free_device(rc);363		return dev_err_probe(dev, ret, "rc_dev registration failed\n");364	}365 366	return 0;367}368 369static const struct of_device_id meson_irtx_dt_match[] = {370	{371		.compatible = "amlogic,meson-g12a-ir-tx",372	},373	{},374};375MODULE_DEVICE_TABLE(of, meson_irtx_dt_match);376 377static struct platform_driver meson_irtx_pd = {378	.probe = meson_irtx_probe,379	.driver = {380		.name = DRIVER_NAME,381		.of_match_table = meson_irtx_dt_match,382	},383};384module_platform_driver(meson_irtx_pd);385 386MODULE_DESCRIPTION("Meson IR TX driver");387MODULE_AUTHOR("Viktor Prutyanov <viktor.prutyanov@phystech.edu>");388MODULE_LICENSE("GPL");389