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