1 // SPDX-License-Identifier: GPL-2.0
2 // SPI driven IR LED device driver
4 // Copyright (c) 2016 Samsung Electronics Co., Ltd.
5 // Copyright (c) Andi Shyti <andi@etezian.org>
7 #include <linux/delay.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>
16 #define IR_SPI_DRIVER_NAME "ir-spi"
18 #define IR_SPI_DEFAULT_FREQUENCY 38000
19 #define IR_SPI_MAX_BUFSIZE 4096
25 u16 tx_buf
[IR_SPI_MAX_BUFSIZE
];
30 struct spi_device
*spi
;
31 struct regulator
*regulator
;
34 static int ir_spi_tx(struct rc_dev
*dev
,
35 unsigned int *buffer
, unsigned int count
)
40 struct ir_spi_data
*idata
= dev
->priv
;
41 struct spi_transfer xfer
;
43 /* convert the pulse/space signal to raw binary signal */
44 for (i
= 0; i
< count
; i
++) {
49 periods
= DIV_ROUND_CLOSEST(buffer
[i
] * idata
->freq
, 1000000);
51 if (len
+ periods
>= IR_SPI_MAX_BUFSIZE
)
55 * the first value in buffer is a pulse, so that 0, 2, 4, ...
56 * contain a pulse duration. On the contrary, 1, 3, 5, ...
57 * contain a space duration.
59 val
= (i
% 2) ? idata
->space
: idata
->pulse
;
60 for (j
= 0; j
< periods
; j
++)
61 idata
->tx_buf
[len
++] = val
;
64 memset(&xfer
, 0, sizeof(xfer
));
66 xfer
.speed_hz
= idata
->freq
* 16;
67 xfer
.len
= len
* sizeof(*idata
->tx_buf
);
68 xfer
.tx_buf
= idata
->tx_buf
;
70 ret
= regulator_enable(idata
->regulator
);
74 ret
= spi_sync_transfer(idata
->spi
, &xfer
, 1);
76 dev_err(&idata
->spi
->dev
, "unable to deliver the signal\n");
78 regulator_disable(idata
->regulator
);
80 return ret
? ret
: count
;
83 static int ir_spi_set_tx_carrier(struct rc_dev
*dev
, u32 carrier
)
85 struct ir_spi_data
*idata
= dev
->priv
;
90 idata
->freq
= carrier
;
95 static int ir_spi_set_duty_cycle(struct rc_dev
*dev
, u32 duty_cycle
)
97 struct ir_spi_data
*idata
= dev
->priv
;
98 int bits
= (duty_cycle
* 15) / 100;
100 idata
->pulse
= GENMASK(bits
, 0);
102 if (idata
->negated
) {
103 idata
->pulse
= ~idata
->pulse
;
104 idata
->space
= 0xffff;
112 static int ir_spi_probe(struct spi_device
*spi
)
116 struct ir_spi_data
*idata
;
118 idata
= devm_kzalloc(&spi
->dev
, sizeof(*idata
), GFP_KERNEL
);
122 idata
->regulator
= devm_regulator_get(&spi
->dev
, "irda_regulator");
123 if (IS_ERR(idata
->regulator
))
124 return PTR_ERR(idata
->regulator
);
126 idata
->rc
= devm_rc_allocate_device(&spi
->dev
, RC_DRIVER_IR_RAW_TX
);
130 idata
->rc
->tx_ir
= ir_spi_tx
;
131 idata
->rc
->s_tx_carrier
= ir_spi_set_tx_carrier
;
132 idata
->rc
->s_tx_duty_cycle
= ir_spi_set_duty_cycle
;
133 idata
->rc
->device_name
= "IR SPI";
134 idata
->rc
->driver_name
= IR_SPI_DRIVER_NAME
;
135 idata
->rc
->priv
= idata
;
138 idata
->negated
= of_property_read_bool(spi
->dev
.of_node
,
140 ret
= of_property_read_u8(spi
->dev
.of_node
, "duty-cycle", &dc
);
144 /* ir_spi_set_duty_cycle cannot fail,
145 * it returns int to be compatible with the
146 * rc->s_tx_duty_cycle function
148 ir_spi_set_duty_cycle(idata
->rc
, dc
);
150 idata
->freq
= IR_SPI_DEFAULT_FREQUENCY
;
152 return devm_rc_register_device(&spi
->dev
, idata
->rc
);
155 static int ir_spi_remove(struct spi_device
*spi
)
160 static const struct of_device_id ir_spi_of_match
[] = {
161 { .compatible
= "ir-spi-led" },
165 static struct spi_driver ir_spi_driver
= {
166 .probe
= ir_spi_probe
,
167 .remove
= ir_spi_remove
,
169 .name
= IR_SPI_DRIVER_NAME
,
170 .of_match_table
= ir_spi_of_match
,
174 module_spi_driver(ir_spi_driver
);
176 MODULE_AUTHOR("Andi Shyti <andi@etezian.org>");
177 MODULE_DESCRIPTION("SPI IR LED");
178 MODULE_LICENSE("GPL v2");