This commit is contained in:
Kuba Birecki 2024-09-02 10:07:56 -05:00 committed by GitHub
commit ff29de56df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 651 additions and 0 deletions

View file

@ -0,0 +1,363 @@
# Copyright (c) 2020, The ZMK Contributors
# SPDX-License-Identifier: MIT
description: ISSI IS31FL3743A LED Matrix driver
compatible: "issi,is31fl3743a"
include: i2c-device.yaml
properties:
sw-setting:
type: int
required: false
enum:
- 0x00
- 0x01
- 0x02
- 0x03
- 0x04
- 0x05
- 0x06
- 0x07
- 0x08
- 0x09
- 0x0a
default: 0x00
description: |
SW setting used to control the matrix size by turning off SWx pins
as described in the datasheet.
map:
type: array
required: true
description: |
Configure how RGB pixels are mapped to individual pixel registers.
r-ext:
type: int
required: true
description: Rext resistor value in kiloohms.
led-max-current:
type: int
required: true
description: Maximum current for each LED in mA. The chip supports up to 34mA.
sync:
type: int
enum:
- 0x00
- 0x10
- 0x11
required: false
default: 0x00
description: |
Controls the SYNC function. Set to 0x11 to set the device as main or 0x10 for secondary. 0x00 for 'off'.
sdb-gpios:
type: phandle-array
required: false
description: |
GPIO pin for hardware shutdown functionality.
chain-length:
type: int
required: true
description: |
How many RGB LEDs are driven by the IC.
scaling-red:
type: int
required: false
default: 255
description: |
Current scaling factor for red channel LEDs on a scale of 0-255.
This setting adjusts the brightness of red pixels relative to other channels by scaling
the amount of current flowing through them. 255 equals led-max-current.
scaling-green:
type: int
required: false
default: 255
description: |
Current scaling factor for green channel LEDs on a scale of 0-255.
This setting adjusts the brightness of green pixels relative to other channels by scaling
the amount of current flowing through them. 255 equals led-max-current.
scaling-blue:
type: int
required: false
default: 255
description: |
Current scaling factor for blue channel LEDs on a scale of 0-255.
This setting adjusts the brightness of blue pixels relative to other channels by scaling
the amount of current flowing through them. 255 equals led-max-current.
gamma:
type: array
required: false
description: |
Gamma correction lookup values.
The gamma values make the LED brightness seem more linear to human eyes.
Default values match the recommendation from the IC datasheet but note that this may
or may not apply for your particular LEDs.
default:
[
0,
0,
0,
0,
1,
1,
1,
1,
2,
2,
2,
2,
3,
3,
3,
3,
4,
4,
4,
4,
5,
5,
5,
5,
6,
6,
6,
6,
7,
7,
7,
7,
8,
8,
8,
8,
10,
10,
10,
10,
12,
12,
12,
12,
14,
14,
14,
14,
16,
16,
16,
16,
18,
18,
18,
18,
20,
20,
20,
20,
22,
22,
22,
22,
24,
24,
24,
24,
26,
26,
26,
26,
29,
29,
29,
29,
32,
32,
32,
32,
35,
35,
35,
35,
38,
38,
38,
38,
41,
41,
41,
41,
44,
44,
44,
44,
47,
47,
47,
47,
50,
50,
50,
50,
53,
53,
53,
53,
57,
57,
57,
57,
61,
61,
61,
61,
65,
65,
65,
65,
69,
69,
69,
69,
73,
73,
73,
73,
77,
77,
77,
77,
81,
81,
81,
81,
85,
85,
85,
85,
89,
89,
89,
89,
94,
94,
94,
94,
99,
99,
99,
99,
104,
104,
104,
104,
109,
109,
109,
109,
114,
114,
114,
114,
119,
119,
119,
119,
124,
124,
124,
124,
129,
129,
129,
129,
134,
134,
134,
134,
140,
140,
140,
140,
146,
146,
146,
146,
152,
152,
152,
152,
158,
158,
158,
158,
164,
164,
164,
164,
170,
170,
170,
170,
176,
176,
176,
176,
182,
182,
182,
182,
188,
188,
188,
188,
195,
195,
195,
195,
202,
202,
202,
202,
209,
209,
209,
209,
216,
216,
216,
216,
223,
223,
223,
223,
230,
230,
230,
230,
237,
237,
237,
237,
244,
244,
244,
244,
251,
251,
251,
251,
255,
255,
255,
255,
]

View file

@ -0,0 +1,10 @@
/*
* Copyright (c) 2024 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#define RGB(com, r, g, b) (com + r)(com + g)(com + b)
#define SW(n) ((n - 1) * 18)
#define CS(n) (n - 1)

View file

@ -5,3 +5,4 @@ add_subdirectory_ifdef(CONFIG_GPIO gpio)
add_subdirectory_ifdef(CONFIG_KSCAN kscan) add_subdirectory_ifdef(CONFIG_KSCAN kscan)
add_subdirectory_ifdef(CONFIG_SENSOR sensor) add_subdirectory_ifdef(CONFIG_SENSOR sensor)
add_subdirectory_ifdef(CONFIG_DISPLAY display) add_subdirectory_ifdef(CONFIG_DISPLAY display)
add_subdirectory_ifdef(CONFIG_LED_STRIP led_strip)

View file

@ -3,5 +3,6 @@
rsource "gpio/Kconfig" rsource "gpio/Kconfig"
rsource "kscan/Kconfig" rsource "kscan/Kconfig"
rsource "led_strip/Kconfig"
rsource "sensor/Kconfig" rsource "sensor/Kconfig"
rsource "display/Kconfig" rsource "display/Kconfig"

View file

@ -0,0 +1,6 @@
# Copyright (c) 2020 The ZMK Contributors
# SPDX-License-Identifier: MIT
zephyr_library_amend()
zephyr_library_sources_ifdef(CONFIG_IS31FL3743A is31fl3743a.c)

View file

@ -0,0 +1,8 @@
# Copyright (c) 2021 The ZMK Contributors
# SPDX-License-Identifier: MIT
if LED_STRIP
rsource "Kconfig.is31fl3743a"
endif # LED_STRIP

View file

@ -0,0 +1,15 @@
# Copyright (c) 2020 The ZMK Contributors
# SPDX-License-Identifier: MIT
config IS31FL3743A
bool "IS31FL3743A LED matrix driver"
depends on I2C
depends on LED_STRIP
help
Enable an IS31FL3743A LED matrix driver.
The IS31FL3743A is a general purpose 18xn(n=1-11) LED matrix
programmed via 1MHz I2C compatible interface. Each LED can be
dimmed individually with 8-bit PWM data and 8-bit DC scaling data
which allows 256 steps of linear PWM dimming and 256 steps of DC
current adjustable levels.

View file

@ -0,0 +1,241 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#define DT_DRV_COMPAT issi_is31fl3743a
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/led_strip.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/math_extras.h>
#include <zephyr/sys/util.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#define IS31FL3743A_REG_PS (0xfd)
#define IS31FL3743A_REG_PSWL (0xfe)
#define IS31FL3743A_PSWL_ENABLE (0xc5)
#define IS31FL3743A_PSWL_DISABLE (0x00)
#define IS31FL3743A_PAGE_PWM (0x00)
#define IS31FL3743A_PAGE_SCALING (0x01)
#define IS31FL3743A_PAGE_FUNCTION (0x02)
struct is31fl3743a_config {
char *label;
struct i2c_dt_spec i2c;
struct gpio_dt_spec gpio;
size_t px_buffer_size;
uint8_t gcc;
uint8_t sws;
uint8_t sync;
uint8_t *rgb_map;
uint8_t *gamma;
uint8_t scaling_red;
uint8_t scaling_green;
uint8_t scaling_blue;
};
struct is31fl3743a_data {
uint8_t *px_buffer;
};
static int is31fl3743a_reg_write(const struct device *dev, uint8_t addr, uint8_t value) {
const struct is31fl3743a_config *config = dev->config;
if (i2c_reg_write_byte_dt(&config->i2c, addr, value)) {
LOG_ERR("Failed writing value %x to register address %x on device %x.", value, addr,
config->i2c.addr);
return -EIO;
}
return 0;
}
static int is31fl3743a_reg_burst_write(const struct device *dev, uint8_t start_addr,
const uint8_t *buffer, size_t num_bytes) {
const struct is31fl3743a_config *config = dev->config;
if (i2c_burst_write_dt(&config->i2c, start_addr, buffer, num_bytes)) {
LOG_ERR("Failed burst write with starting address %x.", start_addr);
return -EIO;
}
return 0;
}
static int is31fl3743a_set_page(const struct device *dev, uint8_t page_addr) {
if (is31fl3743a_reg_write(dev, IS31FL3743A_REG_PSWL, IS31FL3743A_PSWL_ENABLE)) {
return -EIO;
}
if (is31fl3743a_reg_write(dev, IS31FL3743A_REG_PS, page_addr)) {
return -EIO;
}
return 0;
}
static inline bool num_pixels_ok(const struct is31fl3743a_config *config, size_t num_pixels) {
size_t num_bytes;
const bool overflow = size_mul_overflow(num_pixels, 3, &num_bytes);
return !overflow && (num_bytes <= config->px_buffer_size);
}
/**
* Updates individual LED channels without an RGB interpretation.
*/
static int is31fl3743a_strip_update_channels(const struct device *dev, uint8_t *channels,
size_t num_channels) {
const struct is31fl3743a_config *config = dev->config;
if (config->px_buffer_size < num_channels) {
return -ENOMEM;
}
is31fl3743a_set_page(dev, IS31FL3743A_PAGE_PWM);
return is31fl3743a_reg_burst_write(dev, 0x01, channels, num_channels);
}
/*
* Updates the RGB LED matrix according to devicetree's map property.
*/
static int is31fl3743a_strip_update_rgb(const struct device *dev, struct led_rgb *pixels,
size_t num_pixels) {
const struct is31fl3743a_config *config = dev->config;
const struct is31fl3743a_data *data = dev->data;
size_t pixel_idx = 0;
size_t led_idx = 0;
if (!num_pixels_ok(config, num_pixels)) {
return -ENOMEM;
}
while (pixel_idx < num_pixels) {
data->px_buffer[config->rgb_map[led_idx++]] = config->gamma[pixels[pixel_idx].r];
data->px_buffer[config->rgb_map[led_idx++]] = config->gamma[pixels[pixel_idx].g];
data->px_buffer[config->rgb_map[led_idx++]] = config->gamma[pixels[pixel_idx].b];
++pixel_idx;
}
return is31fl3743a_strip_update_channels(dev, data->px_buffer, config->px_buffer_size);
}
/*
* Initiates a driver instance for IS31FL3743A.
*
* If available, SDB is pulled high to enable chip operation,
* followed by a reset to clear out all previous values.
*
* Function and scaling registers are then pre-configured based on devicetree settings.
*/
int static is31fl3743a_init(const struct device *dev) {
const struct is31fl3743a_config *config = dev->config;
const struct is31fl3743a_data *data = dev->data;
if (!device_is_ready(config->i2c.bus)) {
LOG_ERR("I2C device %s is not ready", config->i2c.bus->name);
return -ENODEV;
}
if (!device_is_ready(config->gpio.port)) {
LOG_ERR("GPIO device for %s is not ready", config->label);
return -ENODEV;
}
if (gpio_pin_configure_dt(&config->gpio, GPIO_OUTPUT)) {
LOG_ERR("SDB pin for %s cannot be configured", config->label);
return -EIO;
}
if (gpio_pin_set_dt(&config->gpio, 1)) {
LOG_ERR("SDB pin for %s cannot be pulled high", config->label);
return -EIO;
}
// Reset settings
is31fl3743a_set_page(dev, IS31FL3743A_PAGE_FUNCTION);
is31fl3743a_reg_write(dev, 0x2f, 0xae);
// Set configuration & GCC registers
is31fl3743a_set_page(dev, IS31FL3743A_PAGE_FUNCTION);
is31fl3743a_reg_write(dev, 0x00, (config->sws << 4) | (0x01 << 3) | 0x01); // Configuration
is31fl3743a_reg_write(dev, 0x01, config->gcc); // GCC
// Set scaling registers
uint8_t *px_buffer = data->px_buffer;
uint8_t *rgb_map = config->rgb_map;
for (size_t i = 0; i < config->px_buffer_size; i += 3) {
px_buffer[rgb_map[i]] = config->scaling_red;
px_buffer[rgb_map[i + 1]] = config->scaling_green;
px_buffer[rgb_map[i + 2]] = config->scaling_blue;
}
is31fl3743a_set_page(dev, IS31FL3743A_PAGE_SCALING);
is31fl3743a_reg_burst_write(dev, 0x01, px_buffer, num_pixels);
// Re-initialize px_buffer to prevent any scaling values from sticking around
// when updating PWN registers during normal operation.
for (size_t i = 0; i < config->px_buffer_size; ++i) {
px_buffer[i] = 0;
}
return 0;
}
static const struct led_strip_driver_api is31fl3743a_api = {
.update_rgb = is31fl3743a_strip_update_rgb,
.update_channels = is31fl3743a_strip_update_channels,
};
#define IS31FL3743A_BUFFER_SIZE(idx) \
IS31FL3743A_CS_PINS *(IS31FL3743A_SW_PINS - DT_INST_PROP(idx, sw_setting))
#define IS31FL3743A_GCC(idx) \
(DT_INST_PROP(idx, r_ext) * DT_INST_PROP(idx, led_max_current) * 256 * 256) / (343 * 255)
#define IS31FL3743A_DEVICE(idx) \
\
static uint8_t is31fl3743a_##idx##_px_buffer[IS31FL3743A_BUFFER_SIZE(idx)]; \
\
static struct is31fl3743a_data is31fl3743a_##idx##_data = { \
.px_buffer = is31fl3743a_##idx##_px_buffer, \
}; \
\
static uint8_t is31fl3743a_##idx##_rgb_map[IS31FL3743A_BUFFER_SIZE(idx)] = \
DT_INST_PROP(idx, map); \
\
static uint8_t is31fl3743a_##idx##_gamma[] = DT_INST_PROP(idx, gamma); \
\
static const struct is31fl3743a_config is31fl3743a_##idx##_config = { \
.label = DT_INST_LABEL(idx), \
.i2c = I2C_DT_SPEC_INST_GET(idx), \
.gpio = GPIO_DT_SPEC_INST_GET(idx, sdb_gpios), \
.px_buffer_size = IS31FL3743A_BUFFER_SIZE(idx), \
.gcc = IS31FL3743A_GCC(idx), \
.sws = DT_INST_PROP(idx, sw_setting), \
.sync = DT_INST_PROP(idx, sync), \
.rgb_map = is31fl3743a_##idx##_rgb_map, \
.gamma = is31fl3743a_##idx##_gamma, \
.scaling_red = DT_INST_PROP(idx, scaling_red), \
.scaling_green = DT_INST_PROP(idx, scaling_green), \
.scaling_blue = DT_INST_PROP(idx, scaling_blue), \
}; \
\
DEVICE_DT_INST_DEFINE(idx, &is31fl3743a_init, NULL, &is31fl3743a_##idx##_data, \
&is31fl3743a_##idx##_config, POST_KERNEL, \
CONFIG_LED_STRIP_INIT_PRIORITY, &is31fl3743a_api);
DT_INST_FOREACH_STATUS_OKAY(IS31FL3743A_DEVICE);

View file

@ -0,0 +1,6 @@
description: |
Driver for the IS31FL3743A LED matrix driver
compatible: "issi,issi_is31fl3743a"
include: i2c-device.yaml