hal_cir.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. /* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
  2. * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
  3. * the the People's Republic of China and other countries.
  4. * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
  5. * DISCLAIMER
  6. * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
  7. * IF YOU NEED TO INTEGRATE THIRD PARTY¡¯S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
  8. * IN ALLWINNERS¡¯SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
  9. * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
  10. * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
  11. * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
  12. * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY¡¯S TECHNOLOGY.
  13. * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
  14. * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
  15. * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
  16. * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
  17. * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18. * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  19. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21. * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  23. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  25. * OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <interrupt.h>
  30. #include <hal_clk.h>
  31. #include <hal_gpio.h>
  32. #include <hal_reset.h>
  33. #include <hal_cfg.h>
  34. #include <script.h>
  35. #include "common_cir.h"
  36. #include "platform_cir.h"
  37. #include "sunxi_hal_cir.h"
  38. #ifdef CONFIG_DRIVERS_IR_DEBUG
  39. #define CIR_INFO(fmt, arg...) printf("%s()%d " fmt, __func__, __LINE__, ##arg)
  40. #else
  41. #define CIR_INFO(fmt, arg...) do{}while(0);
  42. #endif
  43. #define CIR_ERR(fmt, arg...) printf("%s()%d " fmt, __func__, __LINE__, ##arg)
  44. static uint32_t base[CIR_MASTER_NUM] = {
  45. SUNXI_IRADC_PBASE,
  46. };
  47. static uint32_t irq[CIR_MASTER_NUM] = {
  48. SUNXI_IRQ_IRADC,
  49. };
  50. static cir_gpio_t pin[CIR_MASTER_NUM] = {
  51. {GPIOB(7), 5, 0},
  52. };
  53. sunxi_cir_t sunxi_cir[CIR_MASTER_NUM];
  54. void sunxi_cir_callback_register(cir_port_t port, cir_callback_t callback)
  55. {
  56. sunxi_cir_t *cir = &sunxi_cir[port];
  57. cir->callback = callback;
  58. }
  59. static irqreturn_t sunxi_cir_handler(int irq, void *dev)
  60. {
  61. sunxi_cir_t *cir = (sunxi_cir_t *)dev;
  62. uint32_t int_flag, count;
  63. uint32_t reg_data, i = 0;
  64. int_flag = readl(cir->base + CIR_RXSTA);
  65. writel(int_flag, cir->base + CIR_RXSTA);
  66. count = (int_flag & RAC) >> RAC_OFFSET;
  67. for(i = 0; i < count; i++)
  68. {
  69. reg_data = readl(cir->base + CIR_RXFIFO);
  70. if (cir->callback)
  71. cir->callback(cir->port, RA, reg_data);
  72. }
  73. if ((int_flag & ROI) && cir->callback) {
  74. cir->callback(cir->port, ROI, 0);
  75. }
  76. if ((int_flag & RPE) && cir->callback)
  77. {
  78. cir->callback(cir->port, RA, 0);
  79. cir->callback(cir->port, RPE, 0);
  80. }
  81. return 0;
  82. }
  83. void sunxi_cir_mode_enable(cir_port_t port, uint8_t enable)
  84. {
  85. sunxi_cir_t *cir = &sunxi_cir[port];
  86. int reg_val;
  87. if (!cir->status)
  88. return ;
  89. reg_val = readl(cir->base + CIR_CTRL);
  90. if (enable)
  91. reg_val |= CIR_ENABLE;
  92. else
  93. reg_val &= ~CIR_ENABLE;
  94. writel(reg_val, cir->base + CIR_CTRL);
  95. }
  96. void sunxi_cir_mode_config(cir_port_t port, cir_mode_t mode)
  97. {
  98. sunxi_cir_t *cir = &sunxi_cir[port];
  99. int reg_val;
  100. if (!cir->status)
  101. return ;
  102. reg_val = readl(cir->base + CIR_CTRL);
  103. reg_val &= ~CIR_MODE;
  104. reg_val |= (mode << CIR_MODE_OFFSET);
  105. writel(reg_val, cir->base + CIR_CTRL);
  106. }
  107. void sunxi_cir_sample_clock_select(cir_port_t port, cir_sample_clock_t div)
  108. {
  109. sunxi_cir_t *cir = &sunxi_cir[port];
  110. int reg_val = 0;
  111. if (!cir->status)
  112. return ;
  113. reg_val = readl(cir->base + CIR_CONFIG);
  114. if (div == CIR_CLK) {
  115. reg_val &= ~SCS;
  116. reg_val |= SCS2;
  117. } else {
  118. reg_val &= ~SCS2;
  119. reg_val |= div;
  120. }
  121. writel(reg_val, cir->base + CIR_CONFIG);
  122. }
  123. void sunxi_cir_sample_noise_threshold(cir_port_t port, int8_t threshold)
  124. {
  125. sunxi_cir_t *cir = &sunxi_cir[port];
  126. int reg_val = 0;
  127. if (!cir->status || threshold > 0x3f)
  128. return ;
  129. reg_val = readl(cir->base + CIR_CONFIG);
  130. reg_val &= ~NTHR;
  131. reg_val |= (threshold << NTHR_OFFSET);
  132. writel(reg_val, cir->base + CIR_CONFIG);
  133. }
  134. void sunxi_cir_sample_idle_threshold(cir_port_t port, int8_t threshold)
  135. {
  136. sunxi_cir_t *cir = &sunxi_cir[port];
  137. int reg_val = 0;
  138. if (!cir->status || threshold > 0x3f)
  139. return ;
  140. reg_val = readl(cir->base + CIR_CONFIG);
  141. reg_val &= ~ITHR;
  142. reg_val |= (threshold << ITHR_OFFSET);
  143. writel(reg_val, cir->base + CIR_CONFIG);
  144. }
  145. void sunxi_cir_sample_active_threshold(cir_port_t port, int8_t threshold)
  146. {
  147. sunxi_cir_t *cir = &sunxi_cir[port];
  148. int reg_val = 0;
  149. if (!cir->status || threshold > 0x3f)
  150. return ;
  151. reg_val = readl(cir->base + CIR_CONFIG);
  152. reg_val &= ~ATHR;
  153. reg_val |= (threshold << ATHR_OFFSET);
  154. writel(reg_val, cir->base + CIR_CONFIG);
  155. }
  156. void sunxi_cir_sample_active_thrctrl(cir_port_t port, int8_t enable)
  157. {
  158. sunxi_cir_t *cir = &sunxi_cir[port];
  159. int reg_val = 0;
  160. if (!cir->status)
  161. return ;
  162. reg_val = readl(cir->base + CIR_CONFIG);
  163. if (enable)
  164. reg_val |= ATHC;
  165. else
  166. reg_val &= ~ATHC;
  167. writel(reg_val, cir->base + CIR_CONFIG);
  168. }
  169. void sunxi_cir_fifo_level(cir_port_t port, int8_t size)
  170. {
  171. sunxi_cir_t *cir = &sunxi_cir[port];
  172. int reg_val = 0;
  173. if (!cir->status || size > 0x3f + 1)
  174. return ;
  175. reg_val = readl(cir->base + CIR_RXINT);
  176. reg_val &= ~RAL;
  177. reg_val |= ((size -1) << RAL_OFFSET);
  178. writel(reg_val, cir->base + CIR_RXINT);
  179. }
  180. void sunxi_cir_irq_enable(cir_port_t port, int enable)
  181. {
  182. sunxi_cir_t *cir = &sunxi_cir[port];
  183. int reg_val = 0;
  184. if (!cir->status)
  185. return ;
  186. reg_val = readl(cir->base + CIR_RXINT);
  187. reg_val &= ~IRQ_MASK;
  188. enable &= IRQ_MASK;
  189. reg_val |= enable;
  190. writel(reg_val, cir->base + CIR_RXINT);
  191. }
  192. void sunxi_cir_irq_disable(cir_port_t port)
  193. {
  194. sunxi_cir_t *cir = &sunxi_cir[port];
  195. int reg_val = 0;
  196. if (!cir->status)
  197. return ;
  198. reg_val = readl(cir->base + CIR_RXINT);
  199. reg_val &= ~IRQ_MASK;
  200. writel(reg_val, cir->base + CIR_RXINT);
  201. }
  202. void sunxi_cir_signal_invert(cir_port_t port, uint8_t invert)
  203. {
  204. sunxi_cir_t *cir = &sunxi_cir[port];
  205. int reg_val = 0;
  206. if (!cir->status)
  207. return ;
  208. reg_val = readl(cir->base + CIR_RXCTRL);
  209. if (invert)
  210. reg_val |= RPPI;
  211. else
  212. reg_val &= ~RPPI;
  213. writel(reg_val, cir->base + CIR_RXCTRL);
  214. }
  215. void sunxi_cir_module_enable(cir_port_t port, int8_t enable)
  216. {
  217. sunxi_cir_t *cir = &sunxi_cir[port];
  218. int reg_val = 0;
  219. if (!cir->status)
  220. return ;
  221. reg_val = readl(cir->base + CIR_CTRL);
  222. if (enable)
  223. reg_val |= (GEN | RXEN);
  224. else
  225. reg_val &= ~(GEN | RXEN);
  226. writel(reg_val, cir->base + CIR_CTRL);
  227. }
  228. static int sunxi_cir_gpio_init(sunxi_cir_t *cir)
  229. {
  230. user_gpio_set_t irpin = {0};
  231. cir_gpio_t pin_cir;
  232. Hal_Cfg_GetKeyValue("cir", "cir_pin", (int32_t *)&irpin, (sizeof(user_gpio_set_t) + 3) / sizeof(int));
  233. pin_cir.gpio = (irpin.port - 1) * PINS_PER_BANK + irpin.port_num;
  234. pin_cir.enable_mux = irpin.mul_sel;
  235. pin_cir.disable_mux = 0;
  236. return hal_gpio_pinmux_set_function(pin_cir.gpio, pin_cir.enable_mux);
  237. }
  238. static int sunxi_cir_gpio_exit(sunxi_cir_t *cir)
  239. {
  240. cir_gpio_t *cir_pin = cir->pin;
  241. return hal_gpio_pinmux_set_function(cir_pin->gpio, cir_pin->disable_mux);
  242. }
  243. #if defined(CONFIG_ARCH_SUN20IW1)
  244. static int sunxi_cir_clk_init(sunxi_cir_t *cir)
  245. {
  246. int ret = 0;
  247. cir->cir_clk_type_R = HAL_SUNXI_R_CCU;
  248. cir->cir_clk_type_FIXED = HAL_SUNXI_FIXED_CCU;
  249. cir->m_clk_id = CLK_R_APB0_IRRX;
  250. cir->p_clk_id = CLK_SRC_HOSC24M;
  251. cir->b_clk_id = CLK_R_APB0_BUS_IRRX;
  252. cir->mclk = hal_clock_get(cir->cir_clk_type_R, cir->m_clk_id);
  253. if (hal_clock_enable(cir->mclk)) {
  254. CIR_ERR("cir mclk enabled failed\n");
  255. return -1;
  256. }
  257. cir->pclk = hal_clock_get(cir->cir_clk_type_FIXED, cir->p_clk_id);
  258. if (hal_clock_enable(cir->pclk)) {
  259. CIR_ERR("cir pclk enabled failed\n");
  260. return -1;
  261. }
  262. cir->bclk = hal_clock_get(cir->cir_clk_type_R, cir->b_clk_id);
  263. if (hal_clock_enable(cir->bclk)) {
  264. CIR_ERR("cir bclk enabled failed\n");
  265. return -1;
  266. }
  267. ret = hal_clk_set_parent(cir->mclk, cir->pclk);
  268. if (ret) {
  269. printf("hal_clk_set_parent failed\n");
  270. return -1;
  271. }
  272. hal_reset_type_t cir_reset_type = HAL_SUNXI_R_RESET;
  273. hal_reset_id_t cir_reset_id = RST_R_APB0_BUS_IRRX;
  274. cir->cir_reset = hal_reset_control_get(cir_reset_type, cir_reset_id);
  275. if (hal_reset_control_deassert(cir->cir_reset)) {
  276. CIR_ERR("cir reset deassert failed\n");
  277. return -1;
  278. }
  279. return 0;
  280. }
  281. #else
  282. static int sunxi_cir_clk_init(sunxi_cir_t *cir)
  283. {
  284. int ret = 0;
  285. int TEST_CLK_TYPE = 1;
  286. int TEST_CLK_DATA = 1;
  287. int TEST_RESET_TYPE = 1;
  288. int TEST_RESET_DATA = 1;
  289. cir->test_clk_type = TEST_CLK_TYPE;
  290. cir->test_clk_id = TEST_CLK_DATA;
  291. cir->test_clk = hal_clock_get(cir->test_clk_type, cir->test_clk_id);
  292. if (hal_clock_enable(cir->test_clk)) {
  293. CIR_ERR("cir TEST_CLK enabled failed\n");
  294. return -1;
  295. }
  296. hal_reset_type_t cir_reset_type = TEST_RESET_TYPE;
  297. hal_reset_id_t cir_reset_id = TEST_RESET_DATA;
  298. cir->cir_reset = hal_reset_control_get(cir_reset_type, cir_reset_id);
  299. if (hal_reset_control_deassert(cir->cir_reset)) {
  300. CIR_ERR("cir reset deassert failed\n");
  301. return -1;
  302. }
  303. return 0;
  304. }
  305. #endif
  306. #if defined(CONFIG_ARCH_SUN20IW1)
  307. static int sunxi_cir_clk_exit(sunxi_cir_t *cir)
  308. {
  309. hal_clock_disable(cir->bclk);
  310. hal_clock_put(cir->bclk);
  311. hal_clock_disable(cir->pclk);
  312. hal_clock_put(cir->pclk);
  313. hal_clock_disable(cir->mclk);
  314. hal_clock_put(cir->mclk);
  315. hal_reset_control_assert(cir->cir_reset);
  316. hal_reset_control_put(cir->cir_reset);
  317. return 0;
  318. }
  319. #else
  320. static int sunxi_cir_clk_exit(sunxi_cir_t *cir)
  321. {
  322. hal_clock_disable(cir->test_clk);
  323. hal_clock_put(cir->test_clk);
  324. hal_reset_control_assert(cir->cir_reset);
  325. hal_reset_control_put(cir->cir_reset);
  326. return 0;
  327. }
  328. #endif
  329. static cir_status_t sunxi_cir_hw_init(sunxi_cir_t *cir)
  330. {
  331. if (sunxi_cir_clk_init(cir))
  332. return CIR_CLK_ERR;
  333. if (sunxi_cir_gpio_init(cir))
  334. return CIR_PIN_ERR;
  335. if (request_irq(cir->irq, sunxi_cir_handler, 0, "cir-irq", cir)) {
  336. printf("cir request irq err\n");
  337. return CIR_IRQ_ERR;
  338. }
  339. enable_irq(cir->irq);
  340. return CIR_OK;
  341. }
  342. static void sunxi_cir_hw_exit(sunxi_cir_t *cir)
  343. {
  344. disable_irq(cir->irq);
  345. free_irq(cir->irq, cir);
  346. sunxi_cir_gpio_exit(cir);
  347. sunxi_cir_clk_exit(cir);
  348. }
  349. #ifdef CONFIG_STANDBY
  350. void sunxi_cir_suspend(cir_port_t port)
  351. {
  352. sunxi_cir_t *cir = &sunxi_cir[port];
  353. disable_irq(cir->irq);
  354. hal_clock_disable(cir->bclk);
  355. hal_clock_disable(cir->mclk);
  356. sunxi_cir_gpio_exit(cir);
  357. return;
  358. }
  359. void sunxi_cir_resume(cir_port_t port)
  360. {
  361. sunxi_cir_t *cir = &sunxi_cir[port];
  362. sunxi_cir_gpio_init(cir);
  363. sunxi_cir_clk_init(cir);
  364. enable_irq(cir->irq);
  365. return;
  366. }
  367. #endif
  368. cir_status_t sunxi_cir_init(cir_port_t port)
  369. {
  370. sunxi_cir_t *cir = &sunxi_cir[port];
  371. cir_status_t ret = 0;
  372. cir->port = port;
  373. cir->base = base[port];
  374. cir->irq = irq[port];
  375. cir->pin = &pin[port];
  376. cir->status = 1;
  377. ret = sunxi_cir_hw_init(cir);
  378. if (ret)
  379. {
  380. CIR_ERR("cir[%d] hardware init error, ret:%d\n", port, ret);
  381. return ret;
  382. }
  383. return ret;
  384. }
  385. void sunxi_cir_deinit(cir_port_t port)
  386. {
  387. sunxi_cir_t *cir = &sunxi_cir[port];
  388. cir->status = 0;
  389. sunxi_cir_hw_exit(cir);
  390. }