1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2017 Sean Young <sean@mess.org> 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/module.h> 8 #include <linux/pwm.h> 9 #include <linux/delay.h> 10 #include <linux/slab.h> 11 #include <linux/of.h> 12 #include <linux/platform_device.h> 13 #include <media/rc-core.h> 14 15 #define DRIVER_NAME "pwm-ir-tx" 16 #define DEVICE_NAME "PWM IR Transmitter" 17 18 struct pwm_ir { 19 struct pwm_device *pwm; 20 unsigned int carrier; 21 unsigned int duty_cycle; 22 }; 23 24 static const struct of_device_id pwm_ir_of_match[] = { 25 { .compatible = "pwm-ir-tx", }, 26 { .compatible = "nokia,n900-ir" }, 27 { }, 28 }; 29 MODULE_DEVICE_TABLE(of, pwm_ir_of_match); 30 31 static int pwm_ir_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle) 32 { 33 struct pwm_ir *pwm_ir = dev->priv; 34 35 pwm_ir->duty_cycle = duty_cycle; 36 37 return 0; 38 } 39 40 static int pwm_ir_set_carrier(struct rc_dev *dev, u32 carrier) 41 { 42 struct pwm_ir *pwm_ir = dev->priv; 43 44 if (!carrier) 45 return -EINVAL; 46 47 pwm_ir->carrier = carrier; 48 49 return 0; 50 } 51 52 static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, 53 unsigned int count) 54 { 55 struct pwm_ir *pwm_ir = dev->priv; 56 struct pwm_device *pwm = pwm_ir->pwm; 57 struct pwm_state state; 58 int i; 59 ktime_t edge; 60 long delta; 61 62 pwm_init_state(pwm, &state); 63 64 state.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, pwm_ir->carrier); 65 pwm_set_relative_duty_cycle(&state, pwm_ir->duty_cycle, 100); 66 67 edge = ktime_get(); 68 69 for (i = 0; i < count; i++) { 70 state.enabled = !(i % 2); 71 pwm_apply_state(pwm, &state); 72 73 edge = ktime_add_us(edge, txbuf[i]); 74 delta = ktime_us_delta(edge, ktime_get()); 75 if (delta > 0) 76 usleep_range(delta, delta + 10); 77 } 78 79 state.enabled = false; 80 pwm_apply_state(pwm, &state); 81 82 return count; 83 } 84 85 static int pwm_ir_probe(struct platform_device *pdev) 86 { 87 struct pwm_ir *pwm_ir; 88 struct rc_dev *rcdev; 89 int rc; 90 91 pwm_ir = devm_kmalloc(&pdev->dev, sizeof(*pwm_ir), GFP_KERNEL); 92 if (!pwm_ir) 93 return -ENOMEM; 94 95 pwm_ir->pwm = devm_pwm_get(&pdev->dev, NULL); 96 if (IS_ERR(pwm_ir->pwm)) 97 return PTR_ERR(pwm_ir->pwm); 98 99 pwm_ir->carrier = 38000; 100 pwm_ir->duty_cycle = 50; 101 102 rcdev = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW_TX); 103 if (!rcdev) 104 return -ENOMEM; 105 106 rcdev->priv = pwm_ir; 107 rcdev->driver_name = DRIVER_NAME; 108 rcdev->device_name = DEVICE_NAME; 109 rcdev->tx_ir = pwm_ir_tx; 110 rcdev->s_tx_duty_cycle = pwm_ir_set_duty_cycle; 111 rcdev->s_tx_carrier = pwm_ir_set_carrier; 112 113 rc = devm_rc_register_device(&pdev->dev, rcdev); 114 if (rc < 0) 115 dev_err(&pdev->dev, "failed to register rc device\n"); 116 117 return rc; 118 } 119 120 static struct platform_driver pwm_ir_driver = { 121 .probe = pwm_ir_probe, 122 .driver = { 123 .name = DRIVER_NAME, 124 .of_match_table = pwm_ir_of_match, 125 }, 126 }; 127 module_platform_driver(pwm_ir_driver); 128 129 MODULE_DESCRIPTION("PWM IR Transmitter"); 130 MODULE_AUTHOR("Sean Young <sean@mess.org>"); 131 MODULE_LICENSE("GPL"); 132