1 // SPDX-License-Identifier: GPL-2.0 2 // SPI driven IR LED device driver 3 // 4 // Copyright (c) 2016 Samsung Electronics Co., Ltd. 5 // Copyright (c) Andi Shyti <andi.shyti@samsung.com> 6 7 #include <linux/delay.h> 8 #include <linux/fs.h> 9 #include <linux/module.h> 10 #include <linux/mutex.h> 11 #include <linux/of_gpio.h> 12 #include <linux/regulator/consumer.h> 13 #include <linux/spi/spi.h> 14 #include <media/rc-core.h> 15 16 #define IR_SPI_DRIVER_NAME "ir-spi" 17 18 /* pulse value for different duty cycles */ 19 #define IR_SPI_PULSE_DC_50 0xff00 20 #define IR_SPI_PULSE_DC_60 0xfc00 21 #define IR_SPI_PULSE_DC_70 0xf800 22 #define IR_SPI_PULSE_DC_75 0xf000 23 #define IR_SPI_PULSE_DC_80 0xc000 24 #define IR_SPI_PULSE_DC_90 0x8000 25 26 #define IR_SPI_DEFAULT_FREQUENCY 38000 27 #define IR_SPI_BIT_PER_WORD 8 28 #define IR_SPI_MAX_BUFSIZE 4096 29 30 struct ir_spi_data { 31 u32 freq; 32 u8 duty_cycle; 33 bool negated; 34 35 u16 tx_buf[IR_SPI_MAX_BUFSIZE]; 36 u16 pulse; 37 u16 space; 38 39 struct rc_dev *rc; 40 struct spi_device *spi; 41 struct regulator *regulator; 42 }; 43 44 static int ir_spi_tx(struct rc_dev *dev, 45 unsigned int *buffer, unsigned int count) 46 { 47 int i; 48 int ret; 49 unsigned int len = 0; 50 struct ir_spi_data *idata = dev->priv; 51 struct spi_transfer xfer; 52 53 /* convert the pulse/space signal to raw binary signal */ 54 for (i = 0; i < count; i++) { 55 unsigned int periods; 56 int j; 57 u16 val; 58 59 periods = DIV_ROUND_CLOSEST(buffer[i] * idata->freq, 1000000); 60 61 if (len + periods >= IR_SPI_MAX_BUFSIZE) 62 return -EINVAL; 63 64 /* 65 * the first value in buffer is a pulse, so that 0, 2, 4, ... 66 * contain a pulse duration. On the contrary, 1, 3, 5, ... 67 * contain a space duration. 68 */ 69 val = (i % 2) ? idata->space : idata->pulse; 70 for (j = 0; j < periods; j++) 71 idata->tx_buf[len++] = val; 72 } 73 74 memset(&xfer, 0, sizeof(xfer)); 75 76 xfer.speed_hz = idata->freq * 16; 77 xfer.len = len * sizeof(*idata->tx_buf); 78 xfer.tx_buf = idata->tx_buf; 79 80 ret = regulator_enable(idata->regulator); 81 if (ret) 82 return ret; 83 84 ret = spi_sync_transfer(idata->spi, &xfer, 1); 85 if (ret) 86 dev_err(&idata->spi->dev, "unable to deliver the signal\n"); 87 88 regulator_disable(idata->regulator); 89 90 return ret ? ret : count; 91 } 92 93 static int ir_spi_set_tx_carrier(struct rc_dev *dev, u32 carrier) 94 { 95 struct ir_spi_data *idata = dev->priv; 96 97 if (!carrier) 98 return -EINVAL; 99 100 idata->freq = carrier; 101 102 return 0; 103 } 104 105 static int ir_spi_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle) 106 { 107 struct ir_spi_data *idata = dev->priv; 108 109 if (duty_cycle >= 90) 110 idata->pulse = IR_SPI_PULSE_DC_90; 111 else if (duty_cycle >= 80) 112 idata->pulse = IR_SPI_PULSE_DC_80; 113 else if (duty_cycle >= 75) 114 idata->pulse = IR_SPI_PULSE_DC_75; 115 else if (duty_cycle >= 70) 116 idata->pulse = IR_SPI_PULSE_DC_70; 117 else if (duty_cycle >= 60) 118 idata->pulse = IR_SPI_PULSE_DC_60; 119 else 120 idata->pulse = IR_SPI_PULSE_DC_50; 121 122 if (idata->negated) { 123 idata->pulse = ~idata->pulse; 124 idata->space = 0xffff; 125 } else { 126 idata->space = 0; 127 } 128 129 return 0; 130 } 131 132 static int ir_spi_probe(struct spi_device *spi) 133 { 134 int ret; 135 u8 dc; 136 struct ir_spi_data *idata; 137 138 idata = devm_kzalloc(&spi->dev, sizeof(*idata), GFP_KERNEL); 139 if (!idata) 140 return -ENOMEM; 141 142 idata->regulator = devm_regulator_get(&spi->dev, "irda_regulator"); 143 if (IS_ERR(idata->regulator)) 144 return PTR_ERR(idata->regulator); 145 146 idata->rc = devm_rc_allocate_device(&spi->dev, RC_DRIVER_IR_RAW_TX); 147 if (!idata->rc) 148 return -ENOMEM; 149 150 idata->rc->tx_ir = ir_spi_tx; 151 idata->rc->s_tx_carrier = ir_spi_set_tx_carrier; 152 idata->rc->s_tx_duty_cycle = ir_spi_set_duty_cycle; 153 idata->rc->device_name = "IR SPI"; 154 idata->rc->driver_name = IR_SPI_DRIVER_NAME; 155 idata->rc->priv = idata; 156 idata->spi = spi; 157 158 idata->negated = of_property_read_bool(spi->dev.of_node, 159 "led-active-low"); 160 ret = of_property_read_u8(spi->dev.of_node, "duty-cycle", &dc); 161 if (ret) 162 dc = 50; 163 164 /* ir_spi_set_duty_cycle cannot fail, 165 * it returns int to be compatible with the 166 * rc->s_tx_duty_cycle function 167 */ 168 ir_spi_set_duty_cycle(idata->rc, dc); 169 170 idata->freq = IR_SPI_DEFAULT_FREQUENCY; 171 172 return devm_rc_register_device(&spi->dev, idata->rc); 173 } 174 175 static int ir_spi_remove(struct spi_device *spi) 176 { 177 return 0; 178 } 179 180 static const struct of_device_id ir_spi_of_match[] = { 181 { .compatible = "ir-spi-led" }, 182 {}, 183 }; 184 185 static struct spi_driver ir_spi_driver = { 186 .probe = ir_spi_probe, 187 .remove = ir_spi_remove, 188 .driver = { 189 .name = IR_SPI_DRIVER_NAME, 190 .of_match_table = ir_spi_of_match, 191 }, 192 }; 193 194 module_spi_driver(ir_spi_driver); 195 196 MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>"); 197 MODULE_DESCRIPTION("SPI IR LED"); 198 MODULE_LICENSE("GPL v2"); 199