0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/clk.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/module.h>
0016 #include <linux/of_platform.h>
0017 #include <linux/reset.h>
0018 #include <media/rc-core.h>
0019
0020 #define SUNXI_IR_DEV "sunxi-ir"
0021
0022
0023
0024 #define SUNXI_IR_CTL_REG 0x00
0025
0026 #define REG_CTL_GEN BIT(0)
0027
0028 #define REG_CTL_RXEN BIT(1)
0029
0030 #define REG_CTL_MD (BIT(4) | BIT(5))
0031
0032
0033 #define SUNXI_IR_RXCTL_REG 0x10
0034
0035 #define REG_RXCTL_RPPI BIT(2)
0036
0037
0038 #define SUNXI_IR_RXFIFO_REG 0x20
0039
0040
0041 #define SUNXI_IR_RXINT_REG 0x2C
0042
0043 #define REG_RXINT_ROI_EN BIT(0)
0044
0045 #define REG_RXINT_RPEI_EN BIT(1)
0046
0047 #define REG_RXINT_RAI_EN BIT(4)
0048
0049
0050 #define REG_RXINT_RAL(val) ((val) << 8)
0051
0052
0053 #define SUNXI_IR_RXSTA_REG 0x30
0054
0055 #define REG_RXSTA_ROI REG_RXINT_ROI_EN
0056
0057 #define REG_RXSTA_RPE REG_RXINT_RPEI_EN
0058
0059 #define REG_RXSTA_RA REG_RXINT_RAI_EN
0060
0061 #define REG_RXSTA_GET_AC(val) (((val) >> 8) & (ir->fifo_size * 2 - 1))
0062
0063 #define REG_RXSTA_CLEARALL 0xff
0064
0065
0066 #define SUNXI_IR_CIR_REG 0x34
0067
0068 #define REG_CIR_NTHR(val) (((val) << 2) & (GENMASK(7, 2)))
0069
0070 #define REG_CIR_ITHR(val) (((val) << 8) & (GENMASK(15, 8)))
0071
0072
0073 #define SUNXI_IR_BASE_CLK 8000000
0074
0075 #define SUNXI_IR_RXNOISE 1
0076
0077
0078
0079
0080
0081
0082
0083 struct sunxi_ir_quirks {
0084 bool has_reset;
0085 int fifo_size;
0086 };
0087
0088 struct sunxi_ir {
0089 struct rc_dev *rc;
0090 void __iomem *base;
0091 int irq;
0092 int fifo_size;
0093 struct clk *clk;
0094 struct clk *apb_clk;
0095 struct reset_control *rst;
0096 const char *map_name;
0097 };
0098
0099 static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id)
0100 {
0101 unsigned long status;
0102 unsigned char dt;
0103 unsigned int cnt, rc;
0104 struct sunxi_ir *ir = dev_id;
0105 struct ir_raw_event rawir = {};
0106
0107 status = readl(ir->base + SUNXI_IR_RXSTA_REG);
0108
0109
0110 writel(status | REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);
0111
0112 if (status & (REG_RXSTA_RA | REG_RXSTA_RPE)) {
0113
0114 rc = REG_RXSTA_GET_AC(status);
0115
0116 rc = rc > ir->fifo_size ? ir->fifo_size : rc;
0117
0118 for (cnt = 0; cnt < rc; cnt++) {
0119
0120 dt = readb(ir->base + SUNXI_IR_RXFIFO_REG);
0121 rawir.pulse = (dt & 0x80) != 0;
0122 rawir.duration = ((dt & 0x7f) + 1) *
0123 ir->rc->rx_resolution;
0124 ir_raw_event_store_with_filter(ir->rc, &rawir);
0125 }
0126 }
0127
0128 if (status & REG_RXSTA_ROI) {
0129 ir_raw_event_overflow(ir->rc);
0130 } else if (status & REG_RXSTA_RPE) {
0131 ir_raw_event_set_idle(ir->rc, true);
0132 ir_raw_event_handle(ir->rc);
0133 } else {
0134 ir_raw_event_handle(ir->rc);
0135 }
0136
0137 return IRQ_HANDLED;
0138 }
0139
0140
0141 static unsigned int sunxi_ithr_to_usec(unsigned int base_clk, unsigned int ithr)
0142 {
0143 return DIV_ROUND_CLOSEST(USEC_PER_SEC * (ithr + 1),
0144 base_clk / (128 * 64));
0145 }
0146
0147
0148 static unsigned int sunxi_usec_to_ithr(unsigned int base_clk, unsigned int usec)
0149 {
0150
0151 return DIV_ROUND_UP((base_clk / (128 * 64)) * usec, USEC_PER_SEC) - 1;
0152 }
0153
0154 static int sunxi_ir_set_timeout(struct rc_dev *rc_dev, unsigned int timeout)
0155 {
0156 struct sunxi_ir *ir = rc_dev->priv;
0157 unsigned int base_clk = clk_get_rate(ir->clk);
0158
0159 unsigned int ithr = sunxi_usec_to_ithr(base_clk, timeout);
0160
0161 dev_dbg(rc_dev->dev.parent, "setting idle threshold to %u\n", ithr);
0162
0163
0164 writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE) | REG_CIR_ITHR(ithr),
0165 ir->base + SUNXI_IR_CIR_REG);
0166
0167 rc_dev->timeout = sunxi_ithr_to_usec(base_clk, ithr);
0168
0169 return 0;
0170 }
0171
0172 static int sunxi_ir_hw_init(struct device *dev)
0173 {
0174 struct sunxi_ir *ir = dev_get_drvdata(dev);
0175 u32 tmp;
0176 int ret;
0177
0178 ret = reset_control_deassert(ir->rst);
0179 if (ret)
0180 return ret;
0181
0182 ret = clk_prepare_enable(ir->apb_clk);
0183 if (ret) {
0184 dev_err(dev, "failed to enable apb clk\n");
0185 goto exit_assert_reset;
0186 }
0187
0188 ret = clk_prepare_enable(ir->clk);
0189 if (ret) {
0190 dev_err(dev, "failed to enable ir clk\n");
0191 goto exit_disable_apb_clk;
0192 }
0193
0194
0195 writel(REG_CTL_MD, ir->base + SUNXI_IR_CTL_REG);
0196
0197
0198 sunxi_ir_set_timeout(ir->rc, ir->rc->timeout);
0199
0200
0201 writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG);
0202
0203
0204 writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);
0205
0206
0207
0208
0209
0210 writel(REG_RXINT_ROI_EN | REG_RXINT_RPEI_EN |
0211 REG_RXINT_RAI_EN | REG_RXINT_RAL(ir->fifo_size / 2 - 1),
0212 ir->base + SUNXI_IR_RXINT_REG);
0213
0214
0215 tmp = readl(ir->base + SUNXI_IR_CTL_REG);
0216 writel(tmp | REG_CTL_GEN | REG_CTL_RXEN, ir->base + SUNXI_IR_CTL_REG);
0217
0218 return 0;
0219
0220 exit_disable_apb_clk:
0221 clk_disable_unprepare(ir->apb_clk);
0222 exit_assert_reset:
0223 reset_control_assert(ir->rst);
0224
0225 return ret;
0226 }
0227
0228 static void sunxi_ir_hw_exit(struct device *dev)
0229 {
0230 struct sunxi_ir *ir = dev_get_drvdata(dev);
0231
0232 clk_disable_unprepare(ir->clk);
0233 clk_disable_unprepare(ir->apb_clk);
0234 reset_control_assert(ir->rst);
0235 }
0236
0237 static int __maybe_unused sunxi_ir_suspend(struct device *dev)
0238 {
0239 sunxi_ir_hw_exit(dev);
0240
0241 return 0;
0242 }
0243
0244 static int __maybe_unused sunxi_ir_resume(struct device *dev)
0245 {
0246 return sunxi_ir_hw_init(dev);
0247 }
0248
0249 static SIMPLE_DEV_PM_OPS(sunxi_ir_pm_ops, sunxi_ir_suspend, sunxi_ir_resume);
0250
0251 static int sunxi_ir_probe(struct platform_device *pdev)
0252 {
0253 int ret = 0;
0254
0255 struct device *dev = &pdev->dev;
0256 struct device_node *dn = dev->of_node;
0257 const struct sunxi_ir_quirks *quirks;
0258 struct sunxi_ir *ir;
0259 u32 b_clk_freq = SUNXI_IR_BASE_CLK;
0260
0261 ir = devm_kzalloc(dev, sizeof(struct sunxi_ir), GFP_KERNEL);
0262 if (!ir)
0263 return -ENOMEM;
0264
0265 quirks = of_device_get_match_data(&pdev->dev);
0266 if (!quirks) {
0267 dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
0268 return -ENODEV;
0269 }
0270
0271 ir->fifo_size = quirks->fifo_size;
0272
0273
0274 ir->apb_clk = devm_clk_get(dev, "apb");
0275 if (IS_ERR(ir->apb_clk)) {
0276 dev_err(dev, "failed to get a apb clock.\n");
0277 return PTR_ERR(ir->apb_clk);
0278 }
0279 ir->clk = devm_clk_get(dev, "ir");
0280 if (IS_ERR(ir->clk)) {
0281 dev_err(dev, "failed to get a ir clock.\n");
0282 return PTR_ERR(ir->clk);
0283 }
0284
0285
0286 of_property_read_u32(dn, "clock-frequency", &b_clk_freq);
0287
0288
0289 if (quirks->has_reset) {
0290 ir->rst = devm_reset_control_get_exclusive(dev, NULL);
0291 if (IS_ERR(ir->rst))
0292 return PTR_ERR(ir->rst);
0293 }
0294
0295 ret = clk_set_rate(ir->clk, b_clk_freq);
0296 if (ret) {
0297 dev_err(dev, "set ir base clock failed!\n");
0298 return ret;
0299 }
0300 dev_dbg(dev, "set base clock frequency to %d Hz.\n", b_clk_freq);
0301
0302
0303 ir->base = devm_platform_ioremap_resource(pdev, 0);
0304 if (IS_ERR(ir->base)) {
0305 return PTR_ERR(ir->base);
0306 }
0307
0308 ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW);
0309 if (!ir->rc) {
0310 dev_err(dev, "failed to allocate device\n");
0311 return -ENOMEM;
0312 }
0313
0314 ir->rc->priv = ir;
0315 ir->rc->device_name = SUNXI_IR_DEV;
0316 ir->rc->input_phys = "sunxi-ir/input0";
0317 ir->rc->input_id.bustype = BUS_HOST;
0318 ir->rc->input_id.vendor = 0x0001;
0319 ir->rc->input_id.product = 0x0001;
0320 ir->rc->input_id.version = 0x0100;
0321 ir->map_name = of_get_property(dn, "linux,rc-map-name", NULL);
0322 ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY;
0323 ir->rc->dev.parent = dev;
0324 ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
0325
0326 ir->rc->rx_resolution = (USEC_PER_SEC / (b_clk_freq / 64));
0327 ir->rc->timeout = IR_DEFAULT_TIMEOUT;
0328 ir->rc->min_timeout = sunxi_ithr_to_usec(b_clk_freq, 0);
0329 ir->rc->max_timeout = sunxi_ithr_to_usec(b_clk_freq, 255);
0330 ir->rc->s_timeout = sunxi_ir_set_timeout;
0331 ir->rc->driver_name = SUNXI_IR_DEV;
0332
0333 ret = rc_register_device(ir->rc);
0334 if (ret) {
0335 dev_err(dev, "failed to register rc device\n");
0336 goto exit_free_dev;
0337 }
0338
0339 platform_set_drvdata(pdev, ir);
0340
0341
0342 ir->irq = platform_get_irq(pdev, 0);
0343 if (ir->irq < 0) {
0344 ret = ir->irq;
0345 goto exit_free_dev;
0346 }
0347
0348 ret = devm_request_irq(dev, ir->irq, sunxi_ir_irq, 0, SUNXI_IR_DEV, ir);
0349 if (ret) {
0350 dev_err(dev, "failed request irq\n");
0351 goto exit_free_dev;
0352 }
0353
0354 ret = sunxi_ir_hw_init(dev);
0355 if (ret)
0356 goto exit_free_dev;
0357
0358 dev_info(dev, "initialized sunXi IR driver\n");
0359 return 0;
0360
0361 exit_free_dev:
0362 rc_free_device(ir->rc);
0363
0364 return ret;
0365 }
0366
0367 static int sunxi_ir_remove(struct platform_device *pdev)
0368 {
0369 struct sunxi_ir *ir = platform_get_drvdata(pdev);
0370
0371 rc_unregister_device(ir->rc);
0372 sunxi_ir_hw_exit(&pdev->dev);
0373
0374 return 0;
0375 }
0376
0377 static void sunxi_ir_shutdown(struct platform_device *pdev)
0378 {
0379 sunxi_ir_hw_exit(&pdev->dev);
0380 }
0381
0382 static const struct sunxi_ir_quirks sun4i_a10_ir_quirks = {
0383 .has_reset = false,
0384 .fifo_size = 16,
0385 };
0386
0387 static const struct sunxi_ir_quirks sun5i_a13_ir_quirks = {
0388 .has_reset = false,
0389 .fifo_size = 64,
0390 };
0391
0392 static const struct sunxi_ir_quirks sun6i_a31_ir_quirks = {
0393 .has_reset = true,
0394 .fifo_size = 64,
0395 };
0396
0397 static const struct of_device_id sunxi_ir_match[] = {
0398 {
0399 .compatible = "allwinner,sun4i-a10-ir",
0400 .data = &sun4i_a10_ir_quirks,
0401 },
0402 {
0403 .compatible = "allwinner,sun5i-a13-ir",
0404 .data = &sun5i_a13_ir_quirks,
0405 },
0406 {
0407 .compatible = "allwinner,sun6i-a31-ir",
0408 .data = &sun6i_a31_ir_quirks,
0409 },
0410 {}
0411 };
0412 MODULE_DEVICE_TABLE(of, sunxi_ir_match);
0413
0414 static struct platform_driver sunxi_ir_driver = {
0415 .probe = sunxi_ir_probe,
0416 .remove = sunxi_ir_remove,
0417 .shutdown = sunxi_ir_shutdown,
0418 .driver = {
0419 .name = SUNXI_IR_DEV,
0420 .of_match_table = sunxi_ir_match,
0421 .pm = &sunxi_ir_pm_ops,
0422 },
0423 };
0424
0425 module_platform_driver(sunxi_ir_driver);
0426
0427 MODULE_DESCRIPTION("Allwinner sunXi IR controller driver");
0428 MODULE_AUTHOR("Alexsey Shestacov <wingrime@linux-sunxi.org>");
0429 MODULE_LICENSE("GPL");