Compare commits
3 Commits
main
...
add-ktd202
| Author | SHA1 | Date | |
|---|---|---|---|
| a4e3122d42 | |||
| a422d4b6da | |||
| 41ee87a8cc |
@@ -12,6 +12,7 @@ zephyr_library_sources_ifdef(CONFIG_HT16K33 ht16k33.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_IS31FL3194 is31fl3194.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_IS31FL3216A is31fl3216a.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_IS31FL3733 is31fl3733.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_KTD202X ktd202x.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_LEDS_GROUP_MULTICOLOR leds_group_multicolor.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_LED_AXP192_AXP2101 led_axp192.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_LED_DAC led_dac.c)
|
||||
|
||||
@@ -34,6 +34,7 @@ source "drivers/led/Kconfig.ht16k33"
|
||||
source "drivers/led/Kconfig.is31fl3194"
|
||||
source "drivers/led/Kconfig.is31fl3216a"
|
||||
source "drivers/led/Kconfig.is31fl3733"
|
||||
source "drivers/led/Kconfig.ktd202x"
|
||||
source "drivers/led/Kconfig.leds-group-multicolor"
|
||||
source "drivers/led/Kconfig.lp3943"
|
||||
source "drivers/led/Kconfig.lp50xx"
|
||||
|
||||
11
drivers/led/Kconfig.ktd202x
Normal file
11
drivers/led/Kconfig.ktd202x
Normal file
@@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2025 Michael Estes
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config KTD202X
|
||||
bool "KTD202X LED driver"
|
||||
default y
|
||||
depends on DT_HAS_KINETIC_KTD202X_ENABLED
|
||||
select I2C
|
||||
help
|
||||
Enable driver for the Kinetic KTD2026/2027 family of LED
|
||||
controllers.
|
||||
157
drivers/led/ktd202x.c
Normal file
157
drivers/led/ktd202x.c
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Michael Estes
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT kinetic_ktd202x
|
||||
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/led.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/util_macro.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#define KTD202X_REG_RESET 0x00
|
||||
#define KTD202X_REG_PERIOD 0x01
|
||||
#define KTD202X_REG_DUTY 0x02
|
||||
#define KTD202X_REG_LED_EN 0x04
|
||||
#define KTD202X_REG_CURRENT 0x06
|
||||
|
||||
#define KTD202X_MAX_LEDS 4
|
||||
#define KTD202X_RESET_MASK GENMASK(2, 0)
|
||||
#define KTD202X_MAX_PERIOD 16380
|
||||
#define KTD202X_FLASH_PERIOD_MASK GENMASK(6, 0)
|
||||
|
||||
LOG_MODULE_REGISTER(ktd202x, CONFIG_LED_LOG_LEVEL);
|
||||
|
||||
struct ktd202x_cfg {
|
||||
struct i2c_dt_spec i2c;
|
||||
};
|
||||
|
||||
struct ktd202x_data {
|
||||
uint8_t enable;
|
||||
};
|
||||
|
||||
static int ktd202x_write_buffer(const struct i2c_dt_spec *i2c, const uint8_t *buffer,
|
||||
uint32_t num_bytes)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = i2c_write_dt(i2c, buffer, num_bytes);
|
||||
if (status < 0) {
|
||||
LOG_ERR("Could not write buffer: %i", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ktd202x_write_reg(const struct i2c_dt_spec *i2c, uint8_t reg, uint8_t val)
|
||||
{
|
||||
uint8_t buffer[2] = {reg, val};
|
||||
|
||||
return ktd202x_write_buffer(i2c, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
static uint8_t ktd202x_brightness_to_current(uint8_t brightness)
|
||||
{
|
||||
return (0xBFU * brightness) / LED_BRIGHTNESS_MAX;
|
||||
}
|
||||
|
||||
static int ktd202x_led_set_brightness(const struct device *dev, uint32_t led, uint8_t value)
|
||||
{
|
||||
const struct ktd202x_cfg *config = dev->config;
|
||||
struct ktd202x_data *data = dev->data;
|
||||
uint8_t current;
|
||||
int status;
|
||||
|
||||
if (led >= KTD202X_MAX_LEDS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (value == 0) {
|
||||
data->enable &= ~(GENMASK(1, 0) << (led * 2));
|
||||
} else if ((data->enable & (GENMASK(1, 0) << (led * 2))) == 0) {
|
||||
WRITE_BIT(data->enable, led * 2, 1);
|
||||
}
|
||||
|
||||
status = ktd202x_write_reg(&config->i2c, KTD202X_REG_LED_EN, data->enable);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
current = ktd202x_brightness_to_current(value);
|
||||
status = ktd202x_write_reg(&config->i2c, KTD202X_REG_CURRENT + led, current);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ktd202x_led_blink(const struct device *dev, uint32_t led,
|
||||
uint32_t delay_on, uint32_t delay_off)
|
||||
{
|
||||
const struct ktd202x_cfg *cfg = dev->config;
|
||||
struct ktd202x_data *data = dev->data;
|
||||
uint8_t period = 0;
|
||||
uint8_t duty = 0;
|
||||
int status = 0;
|
||||
|
||||
if (delay_on + delay_off > KTD202X_MAX_PERIOD) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (delay_on + delay_off >= 256) {
|
||||
period = ((delay_on + delay_off - 256) / 0x80) & KTD202X_FLASH_PERIOD_MASK;
|
||||
}
|
||||
duty = delay_on * UINT8_MAX / (delay_on + delay_off);
|
||||
|
||||
LOG_DBG("Setting period: %d, duty cycle: %d", period, duty);
|
||||
|
||||
status = ktd202x_write_reg(&cfg->i2c, KTD202X_REG_PERIOD, period);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = ktd202x_write_reg(&cfg->i2c, KTD202X_REG_DUTY, duty);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Set enable for led to PWM */
|
||||
data->enable |= 1 << (led * 2 + 1);
|
||||
status = ktd202x_write_reg(&cfg->i2c, KTD202X_REG_LED_EN, data->enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ktd202x_init(const struct device *dev)
|
||||
{
|
||||
const struct ktd202x_cfg *config = dev->config;
|
||||
|
||||
LOG_DBG("Initializing @0x%x...", config->i2c.addr);
|
||||
|
||||
if (!i2c_is_ready_dt(&config->i2c)) {
|
||||
LOG_ERR("I2C device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* NACK expected - ignore return value */
|
||||
ktd202x_write_reg(&config->i2c, KTD202X_REG_RESET, KTD202X_RESET_MASK);
|
||||
k_sleep(K_USEC(200));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEVICE_API(led, ktd202x_led_api) = {
|
||||
.set_brightness = ktd202x_led_set_brightness,
|
||||
.blink = ktd202x_led_blink,
|
||||
};
|
||||
|
||||
#define KTD202X_INIT(id) \
|
||||
static const struct ktd202x_cfg ktd202x_##id##_cfg = { \
|
||||
.i2c = I2C_DT_SPEC_INST_GET(id), \
|
||||
}; \
|
||||
static struct ktd202x_data ktd202x_##id##_data = {0}; \
|
||||
DEVICE_DT_INST_DEFINE(id, &ktd202x_init, NULL, &ktd202x_##id##_data, &ktd202x_##id##_cfg, \
|
||||
POST_KERNEL, CONFIG_LED_INIT_PRIORITY, &ktd202x_led_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KTD202X_INIT)
|
||||
9
dts/bindings/led/kinetic,ktd202x.yaml
Normal file
9
dts/bindings/led/kinetic,ktd202x.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2025 Michael Estes
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: |
|
||||
KTD202x 3 or 4 channel LED driver
|
||||
|
||||
compatible: "kinetic,ktd202x"
|
||||
|
||||
include: i2c-device.yaml
|
||||
9
samples/drivers/led/ktd202x/CMakeLists.txt
Normal file
9
samples/drivers/led/ktd202x/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(led_pca9633)
|
||||
|
||||
FILE(GLOB app_sources src/*.c)
|
||||
target_sources(app PRIVATE ${app_sources})
|
||||
38
samples/drivers/led/ktd202x/README.rst
Normal file
38
samples/drivers/led/ktd202x/README.rst
Normal file
@@ -0,0 +1,38 @@
|
||||
.. zephyr:code-sample:: ktd202x
|
||||
:name: KTD202X LED
|
||||
:relevant-api: led_interface
|
||||
|
||||
Control 3 LEDs connected to a KTD2026 driver chip.
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
This sample controls 3 LEDs connected to a KTD2026 driver, using the
|
||||
following pattern:
|
||||
|
||||
1. turn on LEDs
|
||||
2. turn off LEDs
|
||||
3. set the brightness to 50%
|
||||
4. turn off LEDs
|
||||
5. blink the LEDs
|
||||
6. turn off LEDs
|
||||
|
||||
Building and Running
|
||||
********************
|
||||
|
||||
Build the application for the :zephyr:board:`nucleo_g431rb` board, and connect
|
||||
a KTD2026 LED driver on the bus I2C Arduino.
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/drivers/led/ktd2026
|
||||
:board: nucleo_g431rb_board
|
||||
:goals: build
|
||||
:compact:
|
||||
|
||||
For flashing the application, refer to the Flashing section of the
|
||||
:zephyr:board:`nucleo_g431rb` board documentation.
|
||||
|
||||
References
|
||||
**********
|
||||
|
||||
- KTD202X: https://www.kinet-ic.com/uploads/web/KTD2026/KTD2026-7-04h.pdf
|
||||
11
samples/drivers/led/ktd202x/app.overlay
Normal file
11
samples/drivers/led/ktd202x/app.overlay
Normal file
@@ -0,0 +1,11 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
&arduino_i2c {
|
||||
status = "okay";
|
||||
clock-frequency = <I2C_BITRATE_STANDARD>;
|
||||
|
||||
ktd202x@30 {
|
||||
compatible = "kinetic,ktd202x";
|
||||
reg = <0x30>;
|
||||
};
|
||||
};
|
||||
3
samples/drivers/led/ktd202x/prj.conf
Normal file
3
samples/drivers/led/ktd202x/prj.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
CONFIG_LOG=y
|
||||
|
||||
CONFIG_LED=y
|
||||
8
samples/drivers/led/ktd202x/sample.yaml
Normal file
8
samples/drivers/led/ktd202x/sample.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
sample:
|
||||
description: Demonstration of the KTD202X LED driver
|
||||
name: KTD202X sample
|
||||
tests:
|
||||
sample.drivers.led.ktd2026:
|
||||
depends_on: arduino_i2c
|
||||
build_only: true
|
||||
tags: LED
|
||||
82
samples/drivers/led/ktd202x/src/main.c
Normal file
82
samples/drivers/led/ktd202x/src/main.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Michael Estes
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <errno.h>
|
||||
#include <zephyr/drivers/led.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(main);
|
||||
|
||||
#define NUM_LEDS 3
|
||||
#define HALF_BRIGHTNESS (LED_BRIGHTNESS_MAX / 2)
|
||||
#define BLINK_DELAY_ON 500
|
||||
#define BLINK_DELAY_OFF 500
|
||||
#define DELAY_TIME_MS 1000
|
||||
#define DELAY_TIME K_MSEC(DELAY_TIME_MS)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const struct device *const led_dev = DEVICE_DT_GET_ANY(kinetic_ktd202x);
|
||||
int i, ret;
|
||||
|
||||
if (!led_dev) {
|
||||
LOG_ERR("No devices with compatible kinetic,ktd202x found");
|
||||
return 0;
|
||||
} else if (!device_is_ready(led_dev)) {
|
||||
LOG_ERR("LED device %s is not ready", led_dev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_INF("Found LED device %s", led_dev->name);
|
||||
LOG_INF("Testing leds");
|
||||
|
||||
while (1) {
|
||||
/* Turn on LEDs one by one */
|
||||
for (i = 0; i < NUM_LEDS; i++) {
|
||||
ret = led_on(led_dev, i);
|
||||
if (ret < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
k_sleep(DELAY_TIME);
|
||||
}
|
||||
|
||||
/* Turn off LEDs one by one */
|
||||
for (i = 0; i < NUM_LEDS; i++) {
|
||||
ret = led_off(led_dev, i);
|
||||
if (ret < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
k_sleep(DELAY_TIME);
|
||||
}
|
||||
|
||||
/* Set the brightness to half max of LEDs one by one */
|
||||
for (i = 0; i < NUM_LEDS; i++) {
|
||||
ret = led_set_brightness(led_dev, i, HALF_BRIGHTNESS);
|
||||
if (ret < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
k_sleep(DELAY_TIME);
|
||||
}
|
||||
|
||||
/* Turn off LEDs one by one */
|
||||
for (i = 0; i < NUM_LEDS; i++) {
|
||||
ret = led_off(led_dev, i);
|
||||
if (ret < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
k_sleep(DELAY_TIME);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user