Last Updated on : 2022-03-02 02:05:58download
The Tuya AVS SDK LED lighting effect driver framework is based on the Linux LED Class extension. Tuya has added an AVSUX Class to the standard Linux LED driver, which implements most of the AVS lighting effect processing logic, which greatly reduces the complexity of lighting effect driver development. You only need to implement a simple LED brightness setting. The interface can realize the lighting effect control of AVS.
Before proceeding with driver migration, you need to understand two important data structures in the driver framework:
struct led_avsux_animation
: Corresponds to a complete LED light effect animation, each animation is composed of several frames.struct led_avsux_pattern
: corresponds to a frame in the LED light effect animation, the driver updates the light effect in units of frames.After getting the original driver of the LED chip, you can transplant it as follows:
Copy the attached linux/drivers/leds/led-class-avsux.c
and include/linux/led-class-avsux.h
to the corresponding kernel directory.
Modify the include/linux/leds.h
header file and add LED_DEV_CAP_AVS_UX
.
+++ b/include/linux/leds.h
@@ -48,6 +48,7 @@ struct led_classdev {
#define SET_BRIGHTNESS_ASYNC (1 << 21)
#define SET_BRIGHTNESS_SYNC (1 << 22)
#define LED_DEV_CAP_FLASH (1 << 23)
+ #define LED_DEV_CAP_AVS_UX (1 << 24)
/* Set LED brightness level */
/* Must not sleep, use a workqueue if needed */
Add AVSUX Class driver framework support in Makefile and Kconfig.
+++ b/drivers/leds/Makefile
@@ -3,6 +3,7 @@
obj-$(CONFIG_NEW_LEDS) += led-core.o
obj-$(CONFIG_LEDS_CLASS) += led-class.o
obj-$(CONFIG_LEDS_CLASS_FLASH) += led-class-flash.o
+obj-$(CONFIG_LEDS_CLASS_AVS_UX) += led-class-avsux.o
obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
+++ b/drivers/leds/Kconfig
@@ -29,6 +29,16 @@ config LEDS_CLASS_FLASH
for the flash related features of a LED device. It can be built
as a module.
+config LEDS_CLASS_AVS_UX
+ tristate "Amazon Alexa Voice Service LED UX Class Support"
+ depends on LEDS_CLASS
+ help
+ This option enables the amazon alexa voice service led sysfs class in /sys/class/leds.
+ It wrapps LED Class and adds AVS ux LEDs specific sysfs attributes
+ and kernel internal API to it. You'll need this to provide support
+ for the AVS related features of a LED device. It can be built
+ as a module.
+
comment "LED drivers"
After completing the above steps, you can use Tuya AVS LED driver framework to develop lighting effect drivers.
LED driver development is very simple, you only need to implement the brightness_set interface and call the led_classdev_avsux_register function to register to the driver framework.
A typical LED brightness setting interface is as follows:
static void led_avs_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct led_classdev_avsux *auled_cdev = lcdev_to_aucdev(led_cdev);
struct led_avsux_animation *animation = auled_cdev->cur_anime;
struct led_avsux_pattern *pattern = animation->cur_pattern;
int max = led_cdev->max_brightness;
u8 red, green, blue;
int i;
if (value > max)
value = max;
/* Set the RGB color of each light */
for (i = 0; i < auled_cdev->num_leds; i++) {
red = pattern->colors[i].red * value / max;
green = pattern->colors[i].green * value / max;
blue = pattern->colors[i].blue * value / max;
led_avs_set_rgb(i, red, green, blue);
}
}
Then register the driver to the Tuya AVS LED driver framework, here is an I2C interface chip as an example.
static int led_avs_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) {
struct led_avs_priv *avs = NULL;
struct device_node *np = i2c->dev.of_node;
struct led_classdev *led_cdev;
int ret = -1;
avs = devm_kzalloc(&i2c->dev, sizeof(*avs), GFP_KERNEL);
if (avs == NULL)
return -ENOMEM;
avs->i2c = i2c;
avs->dev = &i2c->dev;
if (np) {
ret = avs_parse_dt(&i2c->dev, aw20036, np);
if (ret) {
dev_err(&i2c->dev,
"%s: failed to parse device tree node\n",
__func__);
return -EIO;
}
} else {
avs->reset_gpio = -1;
}
if (gpio_is_valid(avs->reset_gpio)) {
ret = devm_gpio_request_one(&i2c->dev, avs->reset_gpio,
GPIOF_OUT_INIT_LOW, "avs_rst");
if (ret) {
dev_err(&i2c->dev, "%s: rst request failed\n",
__func__);
return -EIO;
}
}
avs->regmap = devm_regmap_init_i2c(i2c, &avs_regmap);
if (IS_ERR(avs->regmap)) {
ret = PTR_ERR(avs->regmap);
dev_err(&i2c->dev,
"Failed to allocate register map: %d\n", ret);
return ret;
}
avs_hw_reset(avs);
ret = avs_check_chip_id(avs);
if (ret < 0) {
dev_err(&i2c->dev, "%s: check chip id failed ret=%d\n",
__func__, ret);
}
avs_led_init(avs);
/* Set the type and number of lights */
avs->aucdev.led_type = AVS_UX_TYPE_RADIAL,
avs->aucdev.num_leds = 12,
led_cdev = &aw20036->aucdev.led_cdev;
led_cdev->name = AVS_I2C_NAME;
led_cdev->max_brightness = MAX_BRIGHTNESS; /* Adjust the overall brightness through max brightnees */
led_cdev->brightness_set = led_avs_brightness_set;
led_cdev->flags |= LED_DEV_CAP_AVS_UX; /* Specify AVS lighting effect */
ret = led_classdev_avsux_register(&i2c->dev, &avs->aucdev);
if (ret < 0) {
dev_err(&i2c->dev, "Register avsux led failed:%d\n", ret);
return ret;
}
i2c_set_clientdata(i2c, avs);
return 0;
}
Things to note:
There are currently three types of LEDs.
| Type | Description |
| ----|----|
| AVS_UX_TYPE_SINGLE | Single light |
| AVS_UX_TYPE_RADIAL | Ring light |
| AVS_UX_TYPE_LINEAR | Line light |
#define MAX_NUM_LEDS 12
Tuya provides a general-purpose driver for single-lamp arrays driven by PWM or GPIO.
Copy the attached linux/drivers/leds/leds-pwm-avsux.c
to the corresponding directory of the kernel, and modify the Makefile
.
Then enable pwm in the device tree, and add the following nodes, pwm is modified according to the actual situation:
pwmleds {
compatible = "avs-pwm-leds";
status = "okay";
avs-red {
label = "red";
pwms = <&pwm0 0 10000000 0>;
max-brightness = <255>;
};
avs-green {
label = "green";
pwms = <&pwm1 0 10000000 0>;
max-brightness = <255>;
};
avs-blue {
label = "blue";
pwms = <&pwm2 0 10000000 0>;
max-brightness = <255>;
};
};
If you are using gpio to simulate pwm, copy the attached linux/drivers/pwm/pwm-gpio.c
to the corresponding directory of the kernel, and modify the Makefile. Then add the following content to the device tree, and pwm should be modified according to the actual situation:
pwm0: pwm-gpio-r {
compatible = "pwm-gpio";
#pwm-cells = <3>;
pwm-gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>;
};
pwm1: pwm-gpio-g {
compatible = "pwm-gpio";
#pwm-cells = <3>;
pwm-gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>;
};
pwm2: pwm-gpio-b {
compatible = "pwm-gpio";
#pwm-cells = <3>;
pwm-gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>;
};
In addition, Tuya provides the driver of aw20036 in the attachment, you can refer to and transplant it.
After the driver is compiled and loaded, the following two attribute nodes will be generated under sysfs:
/sys/class/leds/avs-pwm-led/avsux_animation
/sys/class/leds/avs-pwm-led/avsux_select
First prepare a lighting effect file test.aniamtaion, the content is as follows:
20:100000,100000,100000,100000,100000,100000,100000,100000,100000,100000,100000,100000
20:200000,200000,200000,200000,200000,200000,200000,200000,200000,200000,200000,200000
20:300000,300000,300000,300000,300000,300000,300000,300000,300000,300000,300000,300000
20:400000,400000,400000,400000,400000,400000,400000,400000,400000,400000,400000,400000
20:500000,500000,500000,500000,500000,500000,500000,500000,500000,500000,500000,500000
20:600000,600000,600000,600000,600000,600000,600000,600000,600000,600000,600000,600000
20:700000,700000,700000,700000,700000,700000,700000,700000,700000,700000,700000,700000
20:800000,800000,800000,800000,800000,800000,800000,800000,800000,800000,800000,800000
20:900000,900000,900000,900000,900000,900000,900000,900000,900000,900000,900000,900000
20:A00000,A00000,A00000,A00000,A00000,A00000,A00000,A00000,A00000,A00000,A00000,A00000
20:B00000,B00000,B00000,B00000,B00000,B00000,B00000,B00000,B00000,B00000,B00000,B00000
20:C00000,C00000,C00000,C00000,C00000,C00000,C00000,C00000,C00000,C00000,C00000,C00000
Copy the file to the /lib/firmware/
directory of the target board.
Load the lighting effect to the driver:
/ # echo "test test.animation"> /sys/class/leds/avs-pwm-led/avsux_animation
Select and enable lighting effects:
/ # echo "test"> /sys/class/leds/avs-pwm-led/avsux_select
Now, you can see the red light flickering from dark to bright.
The .animation
file describes a complete lighting effect animation, in which each line is a frame and corresponds to a pattern. The specific format is as follows:
Among them, duration represents the display duration of this frame (in milliseconds).
HEX_XX is the hexadecimal RGB value of the corresponding lamp, and each lamp is separated by ,. It should be noted that values greater than the number of LEDs will be ignored by the driver.
All lighting effects used by AVS have been defined in the attached led_animation directory. Currently, single lights, ring lights and line lights are supported. Customers can modify or add new lighting effects as needed.
In addition to the AVSUX Class driver framework, Tuya also provides the libLedAnimation library to implement more complex LED logic and state machine state management.
The provided API is as follows:
/**
* LedAnimationInit()-Lighting effect initialization function
* @conf: The path of the lighting effect configuration file, when it is NULL, it will be loaded from /etc/led_config.json by default
*/
ledHandle_t LedAnimationInit(const char *conf);
/**
* LedAnimationUpdate()-Lighting effect update function
* @handle: Handle returned by LedAnimationInit()
* @animation: Animation name defined in the configuration file
*/
int LedAnimationUpdate(ledHandle_t* handle, const char* animation);
int LedAnimationRelease(ledHandle_t* handle);
The syntax of the lighting effect configuration file /etc/led_config.json
is as follows:
device | Description |
---|---|
device | sysfs path of LED driver |
type | Type of LED |
animations | Supported lighting effects |
And each lighting effect contains the following attributes:
Properties | Description |
---|---|
fw_path | Light effect animation file path (relative path under /lib/firmware). |
priority | Lighting effect priority. High-priority lighting effects can interrupt the coverage of low-priority lighting effects. |
loop | The number of loops of the lighting effect animation. 0 means infinite loop. |
pause | Pause time between two loops. |
{
"device": "/sys/class/leds/avs-pwm-led",
"type": "single"
"animations": {
"idle": {
"fw_path": "led_animation/single/idle.animation",
"priority": "1",
"loop": "0",
"pause":"0"
},
"bootup": {
"fw_path": "led_animation/single/bootup.animation",
"priority": "0",
"loop": "0",
"pause":"0"
},
"listening_start": {
"fw_path": "led_animation/single/active-waking.animation",
"priority": "0",
"loop": "0",
"pause":"0"
},
......
Is this page helpful?
YesFeedbackIs this page helpful?
YesFeedback