18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013 STMicroelectronics Limited 48c2ecf20Sopenharmony_ci * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <linux/kernel.h> 78c2ecf20Sopenharmony_ci#include <linux/clk.h> 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/of.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/reset.h> 138c2ecf20Sopenharmony_ci#include <media/rc-core.h> 148c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 158c2ecf20Sopenharmony_ci#include <linux/pm_wakeirq.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct st_rc_device { 188c2ecf20Sopenharmony_ci struct device *dev; 198c2ecf20Sopenharmony_ci int irq; 208c2ecf20Sopenharmony_ci int irq_wake; 218c2ecf20Sopenharmony_ci struct clk *sys_clock; 228c2ecf20Sopenharmony_ci void __iomem *base; /* Register base address */ 238c2ecf20Sopenharmony_ci void __iomem *rx_base;/* RX Register base address */ 248c2ecf20Sopenharmony_ci struct rc_dev *rdev; 258c2ecf20Sopenharmony_ci bool overclocking; 268c2ecf20Sopenharmony_ci int sample_mult; 278c2ecf20Sopenharmony_ci int sample_div; 288c2ecf20Sopenharmony_ci bool rxuhfmode; 298c2ecf20Sopenharmony_ci struct reset_control *rstc; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Registers */ 338c2ecf20Sopenharmony_ci#define IRB_SAMPLE_RATE_COMM 0x64 /* sample freq divisor*/ 348c2ecf20Sopenharmony_ci#define IRB_CLOCK_SEL 0x70 /* clock select */ 358c2ecf20Sopenharmony_ci#define IRB_CLOCK_SEL_STATUS 0x74 /* clock status */ 368c2ecf20Sopenharmony_ci/* IRB IR/UHF receiver registers */ 378c2ecf20Sopenharmony_ci#define IRB_RX_ON 0x40 /* pulse time capture */ 388c2ecf20Sopenharmony_ci#define IRB_RX_SYS 0X44 /* sym period capture */ 398c2ecf20Sopenharmony_ci#define IRB_RX_INT_EN 0x48 /* IRQ enable (R/W) */ 408c2ecf20Sopenharmony_ci#define IRB_RX_INT_STATUS 0x4c /* IRQ status (R/W) */ 418c2ecf20Sopenharmony_ci#define IRB_RX_EN 0x50 /* Receive enable */ 428c2ecf20Sopenharmony_ci#define IRB_MAX_SYM_PERIOD 0x54 /* max sym value */ 438c2ecf20Sopenharmony_ci#define IRB_RX_INT_CLEAR 0x58 /* overrun status */ 448c2ecf20Sopenharmony_ci#define IRB_RX_STATUS 0x6c /* receive status */ 458c2ecf20Sopenharmony_ci#define IRB_RX_NOISE_SUPPR 0x5c /* noise suppression */ 468c2ecf20Sopenharmony_ci#define IRB_RX_POLARITY_INV 0x68 /* polarity inverter */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * IRQ set: Enable full FIFO 1 -> bit 3; 508c2ecf20Sopenharmony_ci * Enable overrun IRQ 1 -> bit 2; 518c2ecf20Sopenharmony_ci * Enable last symbol IRQ 1 -> bit 1: 528c2ecf20Sopenharmony_ci * Enable RX interrupt 1 -> bit 0; 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci#define IRB_RX_INTS 0x0f 558c2ecf20Sopenharmony_ci#define IRB_RX_OVERRUN_INT 0x04 568c2ecf20Sopenharmony_ci /* maximum symbol period (microsecs),timeout to detect end of symbol train */ 578c2ecf20Sopenharmony_ci#define MAX_SYMB_TIME 0x5000 588c2ecf20Sopenharmony_ci#define IRB_SAMPLE_FREQ 10000000 598c2ecf20Sopenharmony_ci#define IRB_FIFO_NOT_EMPTY 0xff00 608c2ecf20Sopenharmony_ci#define IRB_OVERFLOW 0x4 618c2ecf20Sopenharmony_ci#define IRB_TIMEOUT 0xffff 628c2ecf20Sopenharmony_ci#define IR_ST_NAME "st-rc" 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void st_rc_send_lirc_timeout(struct rc_dev *rdev) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct ir_raw_event ev = { .timeout = true, .duration = rdev->timeout }; 678c2ecf20Sopenharmony_ci ir_raw_event_store(rdev, &ev); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* 718c2ecf20Sopenharmony_ci * RX graphical example to better understand the difference between ST IR block 728c2ecf20Sopenharmony_ci * output and standard definition used by LIRC (and most of the world!) 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * mark mark 758c2ecf20Sopenharmony_ci * |-IRB_RX_ON-| |-IRB_RX_ON-| 768c2ecf20Sopenharmony_ci * ___ ___ ___ ___ ___ ___ _ 778c2ecf20Sopenharmony_ci * | | | | | | | | | | | | | 788c2ecf20Sopenharmony_ci * | | | | | | space 0 | | | | | | space 1 | 798c2ecf20Sopenharmony_ci * _____| |__| |__| |____________________________| |__| |__| |_____________| 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * |--------------- IRB_RX_SYS -------------|------ IRB_RX_SYS -------| 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * |------------- encoding bit 0 -----------|---- encoding bit 1 -----| 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * ST hardware returns mark (IRB_RX_ON) and total symbol time (IRB_RX_SYS), so 868c2ecf20Sopenharmony_ci * convert to standard mark/space we have to calculate space=(IRB_RX_SYS-mark) 878c2ecf20Sopenharmony_ci * The mark time represents the amount of time the carrier (usually 36-40kHz) 888c2ecf20Sopenharmony_ci * is detected.The above examples shows Pulse Width Modulation encoding where 898c2ecf20Sopenharmony_ci * bit 0 is represented by space>mark. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic irqreturn_t st_rc_rx_interrupt(int irq, void *data) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci unsigned long timeout; 958c2ecf20Sopenharmony_ci unsigned int symbol, mark = 0; 968c2ecf20Sopenharmony_ci struct st_rc_device *dev = data; 978c2ecf20Sopenharmony_ci int last_symbol = 0; 988c2ecf20Sopenharmony_ci u32 status, int_status; 998c2ecf20Sopenharmony_ci struct ir_raw_event ev = {}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (dev->irq_wake) 1028c2ecf20Sopenharmony_ci pm_wakeup_event(dev->dev, 0); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* FIXME: is 10ms good enough ? */ 1058c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(10); 1068c2ecf20Sopenharmony_ci do { 1078c2ecf20Sopenharmony_ci status = readl(dev->rx_base + IRB_RX_STATUS); 1088c2ecf20Sopenharmony_ci if (!(status & (IRB_FIFO_NOT_EMPTY | IRB_OVERFLOW))) 1098c2ecf20Sopenharmony_ci break; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci int_status = readl(dev->rx_base + IRB_RX_INT_STATUS); 1128c2ecf20Sopenharmony_ci if (unlikely(int_status & IRB_RX_OVERRUN_INT)) { 1138c2ecf20Sopenharmony_ci /* discard the entire collection in case of errors! */ 1148c2ecf20Sopenharmony_ci ir_raw_event_reset(dev->rdev); 1158c2ecf20Sopenharmony_ci dev_info(dev->dev, "IR RX overrun\n"); 1168c2ecf20Sopenharmony_ci writel(IRB_RX_OVERRUN_INT, 1178c2ecf20Sopenharmony_ci dev->rx_base + IRB_RX_INT_CLEAR); 1188c2ecf20Sopenharmony_ci continue; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci symbol = readl(dev->rx_base + IRB_RX_SYS); 1228c2ecf20Sopenharmony_ci mark = readl(dev->rx_base + IRB_RX_ON); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (symbol == IRB_TIMEOUT) 1258c2ecf20Sopenharmony_ci last_symbol = 1; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* Ignore any noise */ 1288c2ecf20Sopenharmony_ci if ((mark > 2) && (symbol > 1)) { 1298c2ecf20Sopenharmony_ci symbol -= mark; 1308c2ecf20Sopenharmony_ci if (dev->overclocking) { /* adjustments to timings */ 1318c2ecf20Sopenharmony_ci symbol *= dev->sample_mult; 1328c2ecf20Sopenharmony_ci symbol /= dev->sample_div; 1338c2ecf20Sopenharmony_ci mark *= dev->sample_mult; 1348c2ecf20Sopenharmony_ci mark /= dev->sample_div; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci ev.duration = mark; 1388c2ecf20Sopenharmony_ci ev.pulse = true; 1398c2ecf20Sopenharmony_ci ir_raw_event_store(dev->rdev, &ev); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (!last_symbol) { 1428c2ecf20Sopenharmony_ci ev.duration = symbol; 1438c2ecf20Sopenharmony_ci ev.pulse = false; 1448c2ecf20Sopenharmony_ci ir_raw_event_store(dev->rdev, &ev); 1458c2ecf20Sopenharmony_ci } else { 1468c2ecf20Sopenharmony_ci st_rc_send_lirc_timeout(dev->rdev); 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci last_symbol = 0; 1518c2ecf20Sopenharmony_ci } while (time_is_after_jiffies(timeout)); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci writel(IRB_RX_INTS, dev->rx_base + IRB_RX_INT_CLEAR); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* Empty software fifo */ 1568c2ecf20Sopenharmony_ci ir_raw_event_handle(dev->rdev); 1578c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void st_rc_hardware_init(struct st_rc_device *dev) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci int baseclock, freqdiff; 1638c2ecf20Sopenharmony_ci unsigned int rx_max_symbol_per = MAX_SYMB_TIME; 1648c2ecf20Sopenharmony_ci unsigned int rx_sampling_freq_div; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* Enable the IP */ 1678c2ecf20Sopenharmony_ci reset_control_deassert(dev->rstc); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci clk_prepare_enable(dev->sys_clock); 1708c2ecf20Sopenharmony_ci baseclock = clk_get_rate(dev->sys_clock); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* IRB input pins are inverted internally from high to low. */ 1738c2ecf20Sopenharmony_ci writel(1, dev->rx_base + IRB_RX_POLARITY_INV); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci rx_sampling_freq_div = baseclock / IRB_SAMPLE_FREQ; 1768c2ecf20Sopenharmony_ci writel(rx_sampling_freq_div, dev->base + IRB_SAMPLE_RATE_COMM); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci freqdiff = baseclock - (rx_sampling_freq_div * IRB_SAMPLE_FREQ); 1798c2ecf20Sopenharmony_ci if (freqdiff) { /* over clocking, workout the adjustment factors */ 1808c2ecf20Sopenharmony_ci dev->overclocking = true; 1818c2ecf20Sopenharmony_ci dev->sample_mult = 1000; 1828c2ecf20Sopenharmony_ci dev->sample_div = baseclock / (10000 * rx_sampling_freq_div); 1838c2ecf20Sopenharmony_ci rx_max_symbol_per = (rx_max_symbol_per * 1000)/dev->sample_div; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci writel(rx_max_symbol_per, dev->rx_base + IRB_MAX_SYM_PERIOD); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int st_rc_remove(struct platform_device *pdev) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct st_rc_device *rc_dev = platform_get_drvdata(pdev); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci dev_pm_clear_wake_irq(&pdev->dev); 1948c2ecf20Sopenharmony_ci device_init_wakeup(&pdev->dev, false); 1958c2ecf20Sopenharmony_ci clk_disable_unprepare(rc_dev->sys_clock); 1968c2ecf20Sopenharmony_ci rc_unregister_device(rc_dev->rdev); 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int st_rc_open(struct rc_dev *rdev) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct st_rc_device *dev = rdev->priv; 2038c2ecf20Sopenharmony_ci unsigned long flags; 2048c2ecf20Sopenharmony_ci local_irq_save(flags); 2058c2ecf20Sopenharmony_ci /* enable interrupts and receiver */ 2068c2ecf20Sopenharmony_ci writel(IRB_RX_INTS, dev->rx_base + IRB_RX_INT_EN); 2078c2ecf20Sopenharmony_ci writel(0x01, dev->rx_base + IRB_RX_EN); 2088c2ecf20Sopenharmony_ci local_irq_restore(flags); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic void st_rc_close(struct rc_dev *rdev) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct st_rc_device *dev = rdev->priv; 2168c2ecf20Sopenharmony_ci /* disable interrupts and receiver */ 2178c2ecf20Sopenharmony_ci writel(0x00, dev->rx_base + IRB_RX_EN); 2188c2ecf20Sopenharmony_ci writel(0x00, dev->rx_base + IRB_RX_INT_EN); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int st_rc_probe(struct platform_device *pdev) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci int ret = -EINVAL; 2248c2ecf20Sopenharmony_ci struct rc_dev *rdev; 2258c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2268c2ecf20Sopenharmony_ci struct resource *res; 2278c2ecf20Sopenharmony_ci struct st_rc_device *rc_dev; 2288c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 2298c2ecf20Sopenharmony_ci const char *rx_mode; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci rc_dev = devm_kzalloc(dev, sizeof(struct st_rc_device), GFP_KERNEL); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (!rc_dev) 2348c2ecf20Sopenharmony_ci return -ENOMEM; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci rdev = rc_allocate_device(RC_DRIVER_IR_RAW); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (!rdev) 2398c2ecf20Sopenharmony_ci return -ENOMEM; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (np && !of_property_read_string(np, "rx-mode", &rx_mode)) { 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (!strcmp(rx_mode, "uhf")) { 2448c2ecf20Sopenharmony_ci rc_dev->rxuhfmode = true; 2458c2ecf20Sopenharmony_ci } else if (!strcmp(rx_mode, "infrared")) { 2468c2ecf20Sopenharmony_ci rc_dev->rxuhfmode = false; 2478c2ecf20Sopenharmony_ci } else { 2488c2ecf20Sopenharmony_ci dev_err(dev, "Unsupported rx mode [%s]\n", rx_mode); 2498c2ecf20Sopenharmony_ci goto err; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci } else { 2538c2ecf20Sopenharmony_ci goto err; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci rc_dev->sys_clock = devm_clk_get(dev, NULL); 2578c2ecf20Sopenharmony_ci if (IS_ERR(rc_dev->sys_clock)) { 2588c2ecf20Sopenharmony_ci dev_err(dev, "System clock not found\n"); 2598c2ecf20Sopenharmony_ci ret = PTR_ERR(rc_dev->sys_clock); 2608c2ecf20Sopenharmony_ci goto err; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci rc_dev->irq = platform_get_irq(pdev, 0); 2648c2ecf20Sopenharmony_ci if (rc_dev->irq < 0) { 2658c2ecf20Sopenharmony_ci ret = rc_dev->irq; 2668c2ecf20Sopenharmony_ci goto err; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci rc_dev->base = devm_ioremap_resource(dev, res); 2728c2ecf20Sopenharmony_ci if (IS_ERR(rc_dev->base)) { 2738c2ecf20Sopenharmony_ci ret = PTR_ERR(rc_dev->base); 2748c2ecf20Sopenharmony_ci goto err; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (rc_dev->rxuhfmode) 2788c2ecf20Sopenharmony_ci rc_dev->rx_base = rc_dev->base + 0x40; 2798c2ecf20Sopenharmony_ci else 2808c2ecf20Sopenharmony_ci rc_dev->rx_base = rc_dev->base; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci rc_dev->rstc = reset_control_get_optional_exclusive(dev, NULL); 2838c2ecf20Sopenharmony_ci if (IS_ERR(rc_dev->rstc)) { 2848c2ecf20Sopenharmony_ci ret = PTR_ERR(rc_dev->rstc); 2858c2ecf20Sopenharmony_ci goto err; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci rc_dev->dev = dev; 2898c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, rc_dev); 2908c2ecf20Sopenharmony_ci st_rc_hardware_init(rc_dev); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; 2938c2ecf20Sopenharmony_ci /* rx sampling rate is 10Mhz */ 2948c2ecf20Sopenharmony_ci rdev->rx_resolution = 100; 2958c2ecf20Sopenharmony_ci rdev->timeout = MAX_SYMB_TIME; 2968c2ecf20Sopenharmony_ci rdev->priv = rc_dev; 2978c2ecf20Sopenharmony_ci rdev->open = st_rc_open; 2988c2ecf20Sopenharmony_ci rdev->close = st_rc_close; 2998c2ecf20Sopenharmony_ci rdev->driver_name = IR_ST_NAME; 3008c2ecf20Sopenharmony_ci rdev->map_name = RC_MAP_EMPTY; 3018c2ecf20Sopenharmony_ci rdev->device_name = "ST Remote Control Receiver"; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci ret = rc_register_device(rdev); 3048c2ecf20Sopenharmony_ci if (ret < 0) 3058c2ecf20Sopenharmony_ci goto clkerr; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci rc_dev->rdev = rdev; 3088c2ecf20Sopenharmony_ci if (devm_request_irq(dev, rc_dev->irq, st_rc_rx_interrupt, 3098c2ecf20Sopenharmony_ci 0, IR_ST_NAME, rc_dev) < 0) { 3108c2ecf20Sopenharmony_ci dev_err(dev, "IRQ %d register failed\n", rc_dev->irq); 3118c2ecf20Sopenharmony_ci ret = -EINVAL; 3128c2ecf20Sopenharmony_ci goto rcerr; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* enable wake via this device */ 3168c2ecf20Sopenharmony_ci device_init_wakeup(dev, true); 3178c2ecf20Sopenharmony_ci dev_pm_set_wake_irq(dev, rc_dev->irq); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* 3208c2ecf20Sopenharmony_ci * for LIRC_MODE_MODE2 or LIRC_MODE_PULSE or LIRC_MODE_RAW 3218c2ecf20Sopenharmony_ci * lircd expects a long space first before a signal train to sync. 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ci st_rc_send_lirc_timeout(rdev); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci dev_info(dev, "setup in %s mode\n", rc_dev->rxuhfmode ? "UHF" : "IR"); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return ret; 3288c2ecf20Sopenharmony_circerr: 3298c2ecf20Sopenharmony_ci rc_unregister_device(rdev); 3308c2ecf20Sopenharmony_ci rdev = NULL; 3318c2ecf20Sopenharmony_ciclkerr: 3328c2ecf20Sopenharmony_ci clk_disable_unprepare(rc_dev->sys_clock); 3338c2ecf20Sopenharmony_cierr: 3348c2ecf20Sopenharmony_ci rc_free_device(rdev); 3358c2ecf20Sopenharmony_ci dev_err(dev, "Unable to register device (%d)\n", ret); 3368c2ecf20Sopenharmony_ci return ret; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 3408c2ecf20Sopenharmony_cistatic int st_rc_suspend(struct device *dev) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct st_rc_device *rc_dev = dev_get_drvdata(dev); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (device_may_wakeup(dev)) { 3458c2ecf20Sopenharmony_ci if (!enable_irq_wake(rc_dev->irq)) 3468c2ecf20Sopenharmony_ci rc_dev->irq_wake = 1; 3478c2ecf20Sopenharmony_ci else 3488c2ecf20Sopenharmony_ci return -EINVAL; 3498c2ecf20Sopenharmony_ci } else { 3508c2ecf20Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 3518c2ecf20Sopenharmony_ci writel(0x00, rc_dev->rx_base + IRB_RX_EN); 3528c2ecf20Sopenharmony_ci writel(0x00, rc_dev->rx_base + IRB_RX_INT_EN); 3538c2ecf20Sopenharmony_ci clk_disable_unprepare(rc_dev->sys_clock); 3548c2ecf20Sopenharmony_ci reset_control_assert(rc_dev->rstc); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic int st_rc_resume(struct device *dev) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct st_rc_device *rc_dev = dev_get_drvdata(dev); 3638c2ecf20Sopenharmony_ci struct rc_dev *rdev = rc_dev->rdev; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (rc_dev->irq_wake) { 3668c2ecf20Sopenharmony_ci disable_irq_wake(rc_dev->irq); 3678c2ecf20Sopenharmony_ci rc_dev->irq_wake = 0; 3688c2ecf20Sopenharmony_ci } else { 3698c2ecf20Sopenharmony_ci pinctrl_pm_select_default_state(dev); 3708c2ecf20Sopenharmony_ci st_rc_hardware_init(rc_dev); 3718c2ecf20Sopenharmony_ci if (rdev->users) { 3728c2ecf20Sopenharmony_ci writel(IRB_RX_INTS, rc_dev->rx_base + IRB_RX_INT_EN); 3738c2ecf20Sopenharmony_ci writel(0x01, rc_dev->rx_base + IRB_RX_EN); 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci return 0; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci#endif 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(st_rc_pm_ops, st_rc_suspend, st_rc_resume); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 3858c2ecf20Sopenharmony_cistatic const struct of_device_id st_rc_match[] = { 3868c2ecf20Sopenharmony_ci { .compatible = "st,comms-irb", }, 3878c2ecf20Sopenharmony_ci {}, 3888c2ecf20Sopenharmony_ci}; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, st_rc_match); 3918c2ecf20Sopenharmony_ci#endif 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic struct platform_driver st_rc_driver = { 3948c2ecf20Sopenharmony_ci .driver = { 3958c2ecf20Sopenharmony_ci .name = IR_ST_NAME, 3968c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(st_rc_match), 3978c2ecf20Sopenharmony_ci .pm = &st_rc_pm_ops, 3988c2ecf20Sopenharmony_ci }, 3998c2ecf20Sopenharmony_ci .probe = st_rc_probe, 4008c2ecf20Sopenharmony_ci .remove = st_rc_remove, 4018c2ecf20Sopenharmony_ci}; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cimodule_platform_driver(st_rc_driver); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RC Transceiver driver for STMicroelectronics platforms"); 4068c2ecf20Sopenharmony_ciMODULE_AUTHOR("STMicroelectronics (R&D) Ltd"); 4078c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 408