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/bits.h>
8 #include <linux/device.h>
10 #include <linux/math.h>
11 #include <linux/mod_devicetable.h>
12 #include <linux/module.h>
13 #include <linux/property.h>
14 #include <linux/regulator/consumer.h>
15 #include <linux/spi/spi.h>
16 #include <linux/string.h>
17 #include <linux/types.h>
19 #include <media/rc-core.h>
21 #define IR_SPI_DRIVER_NAME "ir-spi"
23 #define IR_SPI_DEFAULT_FREQUENCY 38000
24 #define IR_SPI_MAX_BUFSIZE 4096
30 u16 tx_buf
[IR_SPI_MAX_BUFSIZE
];
35 struct spi_device
*spi
;
36 struct regulator
*regulator
;
39 static int ir_spi_tx(struct rc_dev
*dev
, unsigned int *buffer
, unsigned int count
)
44 struct ir_spi_data
*idata
= dev
->priv
;
45 struct spi_transfer xfer
;
47 /* convert the pulse/space signal to raw binary signal */
48 for (i
= 0; i
< count
; i
++) {
53 periods
= DIV_ROUND_CLOSEST(buffer
[i
] * idata
->freq
, 1000000);
55 if (len
+ periods
>= IR_SPI_MAX_BUFSIZE
)
59 * The first value in buffer is a pulse, so that 0, 2, 4, ...
60 * contain a pulse duration. On the contrary, 1, 3, 5, ...
61 * contain a space duration.
63 val
= (i
% 2) ? idata
->space
: idata
->pulse
;
64 for (j
= 0; j
< periods
; j
++)
65 idata
->tx_buf
[len
++] = val
;
68 memset(&xfer
, 0, sizeof(xfer
));
70 xfer
.speed_hz
= idata
->freq
* 16;
71 xfer
.len
= len
* sizeof(*idata
->tx_buf
);
72 xfer
.tx_buf
= idata
->tx_buf
;
74 ret
= regulator_enable(idata
->regulator
);
78 ret
= spi_sync_transfer(idata
->spi
, &xfer
, 1);
80 dev_err(&idata
->spi
->dev
, "unable to deliver the signal\n");
82 regulator_disable(idata
->regulator
);
84 return ret
? ret
: count
;
87 static int ir_spi_set_tx_carrier(struct rc_dev
*dev
, u32 carrier
)
89 struct ir_spi_data
*idata
= dev
->priv
;
94 idata
->freq
= carrier
;
99 static int ir_spi_set_duty_cycle(struct rc_dev
*dev
, u32 duty_cycle
)
101 struct ir_spi_data
*idata
= dev
->priv
;
102 int bits
= (duty_cycle
* 15) / 100;
104 idata
->pulse
= GENMASK(bits
, 0);
106 if (idata
->negated
) {
107 idata
->pulse
= ~idata
->pulse
;
108 idata
->space
= 0xffff;
116 static int ir_spi_probe(struct spi_device
*spi
)
118 struct device
*dev
= &spi
->dev
;
121 struct ir_spi_data
*idata
;
123 idata
= devm_kzalloc(dev
, sizeof(*idata
), GFP_KERNEL
);
127 idata
->regulator
= devm_regulator_get(dev
, "irda_regulator");
128 if (IS_ERR(idata
->regulator
))
129 return PTR_ERR(idata
->regulator
);
131 idata
->rc
= devm_rc_allocate_device(&spi
->dev
, RC_DRIVER_IR_RAW_TX
);
135 idata
->rc
->tx_ir
= ir_spi_tx
;
136 idata
->rc
->s_tx_carrier
= ir_spi_set_tx_carrier
;
137 idata
->rc
->s_tx_duty_cycle
= ir_spi_set_duty_cycle
;
138 idata
->rc
->device_name
= "IR SPI";
139 idata
->rc
->driver_name
= IR_SPI_DRIVER_NAME
;
140 idata
->rc
->priv
= idata
;
143 idata
->negated
= device_property_read_bool(dev
, "led-active-low");
144 ret
= device_property_read_u8(dev
, "duty-cycle", &dc
);
149 * ir_spi_set_duty_cycle() cannot fail, it returns int
150 * to be compatible with the rc->s_tx_duty_cycle function.
152 ir_spi_set_duty_cycle(idata
->rc
, dc
);
154 idata
->freq
= IR_SPI_DEFAULT_FREQUENCY
;
156 return devm_rc_register_device(dev
, idata
->rc
);
159 static const struct of_device_id ir_spi_of_match
[] = {
160 { .compatible
= "ir-spi-led" },
163 MODULE_DEVICE_TABLE(of
, ir_spi_of_match
);
165 static const struct spi_device_id ir_spi_ids
[] = {
169 MODULE_DEVICE_TABLE(spi
, ir_spi_ids
);
171 static struct spi_driver ir_spi_driver
= {
172 .probe
= ir_spi_probe
,
173 .id_table
= ir_spi_ids
,
175 .name
= IR_SPI_DRIVER_NAME
,
176 .of_match_table
= ir_spi_of_match
,
179 module_spi_driver(ir_spi_driver
);
181 MODULE_AUTHOR("Andi Shyti <andi@etezian.org>");
182 MODULE_DESCRIPTION("SPI IR LED");
183 MODULE_LICENSE("GPL v2");