blob: 8cb4ed43dedf23edf5a089b75339b61b0b02e45d [file] [log] [blame]
Michael Hope8ee282e2018-02-12 22:35:20 +01001/*
2 * Copyright (c) 2018 Google LLC.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
Kumar Gala3bc3f2a2020-03-25 12:01:50 -05007#define DT_DRV_COMPAT apa_apa102
8
Michael Hope8ee282e2018-02-12 22:35:20 +01009#include <errno.h>
Gerard Marull-Paretasfb60aab2022-05-06 10:25:46 +020010#include <zephyr/drivers/led_strip.h>
11#include <zephyr/drivers/spi.h>
12#include <zephyr/drivers/gpio.h>
13#include <zephyr/sys/util.h>
Roman Vaughanac6fec42020-05-14 14:24:10 +120014
Jordan Yates8d846262021-08-07 13:01:52 +100015struct apa102_config {
16 struct spi_dt_spec bus;
Michael Hope8ee282e2018-02-12 22:35:20 +010017};
18
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +020019static int apa102_update(const struct device *dev, void *buf, size_t size)
Michael Hope8ee282e2018-02-12 22:35:20 +010020{
Jordan Yates8d846262021-08-07 13:01:52 +100021 const struct apa102_config *config = dev->config;
22 static const uint8_t zeros[] = { 0, 0, 0, 0 };
23 static const uint8_t ones[] = { 0xFF, 0xFF, 0xFF, 0xFF };
Tomasz Bursztykaea2431f2018-01-30 13:49:01 +010024 const struct spi_buf tx_bufs[] = {
Michael Hope8ee282e2018-02-12 22:35:20 +010025 {
26 /* Start frame: at least 32 zeros */
Kumar Galaa1b77fd2020-05-27 11:26:57 -050027 .buf = (uint8_t *)zeros,
Michael Hope8ee282e2018-02-12 22:35:20 +010028 .len = sizeof(zeros),
29 },
30 {
31 /* LED data itself */
32 .buf = buf,
33 .len = size,
34 },
35 {
36 /* End frame: at least 32 ones to clock the
37 * remaining bits to the LEDs at the end of
38 * the strip.
39 */
Kumar Galaa1b77fd2020-05-27 11:26:57 -050040 .buf = (uint8_t *)ones,
Michael Hope8ee282e2018-02-12 22:35:20 +010041 .len = sizeof(ones),
42 },
43 };
Tomasz Bursztykaea2431f2018-01-30 13:49:01 +010044 const struct spi_buf_set tx = {
45 .buffers = tx_bufs,
Roman Vaughanebf5dfb2018-12-09 04:39:39 +130046 .count = ARRAY_SIZE(tx_bufs)
Tomasz Bursztykaea2431f2018-01-30 13:49:01 +010047 };
Michael Hope8ee282e2018-02-12 22:35:20 +010048
Jordan Yates8d846262021-08-07 13:01:52 +100049 return spi_write_dt(&config->bus, &tx);
Michael Hope8ee282e2018-02-12 22:35:20 +010050}
51
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +020052static int apa102_update_rgb(const struct device *dev, struct led_rgb *pixels,
Michael Hope8ee282e2018-02-12 22:35:20 +010053 size_t count)
54{
Kumar Galaa1b77fd2020-05-27 11:26:57 -050055 uint8_t *p = (uint8_t *)pixels;
Michael Hope8ee282e2018-02-12 22:35:20 +010056 size_t i;
57 /* SOF (3 bits) followed by the 0 to 31 global dimming level */
Kumar Galaa1b77fd2020-05-27 11:26:57 -050058 uint8_t prefix = 0xE0 | 31;
Michael Hope8ee282e2018-02-12 22:35:20 +010059
60 /* Rewrite to the on-wire format */
61 for (i = 0; i < count; i++) {
Kumar Galaa1b77fd2020-05-27 11:26:57 -050062 uint8_t r = pixels[i].r;
63 uint8_t g = pixels[i].g;
64 uint8_t b = pixels[i].b;
Michael Hope8ee282e2018-02-12 22:35:20 +010065
66 *p++ = prefix;
67 *p++ = b;
68 *p++ = g;
69 *p++ = r;
70 }
71
72 BUILD_ASSERT(sizeof(struct led_rgb) == 4);
73 return apa102_update(dev, pixels, sizeof(struct led_rgb) * count);
74}
75
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +020076static int apa102_update_channels(const struct device *dev, uint8_t *channels,
Michael Hope8ee282e2018-02-12 22:35:20 +010077 size_t num_channels)
78{
79 /* Not implemented */
80 return -EINVAL;
81}
82
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +020083static int apa102_init(const struct device *dev)
Michael Hope8ee282e2018-02-12 22:35:20 +010084{
Jordan Yates8d846262021-08-07 13:01:52 +100085 const struct apa102_config *config = dev->config;
Michael Hope8ee282e2018-02-12 22:35:20 +010086
Bartosz Bilase077fb72022-12-03 14:49:05 +010087 if (!spi_is_ready_dt(&config->bus)) {
Michael Hope8ee282e2018-02-12 22:35:20 +010088 return -ENODEV;
89 }
90
Michael Hope8ee282e2018-02-12 22:35:20 +010091 return 0;
92}
93
Jordan Yates8d846262021-08-07 13:01:52 +100094static const struct apa102_config apa102_config = {
95 .bus = SPI_DT_SPEC_INST_GET(
96 0, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 0)
97};
Michael Hope8ee282e2018-02-12 22:35:20 +010098
99static const struct led_strip_driver_api apa102_api = {
100 .update_rgb = apa102_update_rgb,
101 .update_channels = apa102_update_channels,
102};
103
Gerard Marull-Paretas233fbf42021-04-28 11:14:49 +0200104DEVICE_DT_INST_DEFINE(0, apa102_init, NULL,
Jordan Yates8d846262021-08-07 13:01:52 +1000105 NULL, &apa102_config, POST_KERNEL,
106 CONFIG_LED_STRIP_INIT_PRIORITY, &apa102_api);