树莓派-LED篇
Posted skdev
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树莓派-LED篇相关的知识,希望对你有一定的参考价值。
1 leds驱动
新增文件:arch\\arm\\boot\\dts\\overlays\\example-overlay.dts
/dts-v1/;
/plugin/;
/
compatible = "brcm,bcm2835";
fragment@0
target = <&gpio>;
__overlay__
leds_pins: leds_pins
brcm,pins = <25>;
brcm,function = <1>; /* out */
;
;
;
fragment@1
target = <&i2c_arm>;
__overlay__
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
aw9523b: aw9523b@5b
compatible = "xxx,aw9523b-leds";
reg = <0x5b>;
pinctrl-names = "default";
pinctrl-0 = <&leds_pins>;
reset-gpios = <&gpio 25 0>;
status = "okay";
;
;
;
__overrides__
aw9523b = <&aw9523b>,"status";
;
;
linux\\arch\\arm\\boot\\dts\\overlays\\Makefile
dtbo-$(RPI_DT_OVERLAYS) += example-leds.dtbo
linux\\drivers\\leds\\leds-aw9523b.c
/*
* TI LP8860 4-Channel LED Driver
*
* Copyright (C) 2014 Texas Instruments
*
* Author: Dan Murphy <dmurphy@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*/
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/delay.h>
#define AW9523B_REG_CHIPID 0x10
#define AW9523B_CHIPID_VALUE 0x23
#define AW9523B_LED_OFFSET 3
#define AW9523B_COLOR_OFFSET 3
static struct mutex aw9523b_mutex;
enum led_ids
LED1,
LED2,
LED3,
LED_NUM,
;
enum led_colors
LED1_RED = 0,
LED1_GREEN = 1,
LED1_BLUE = 2,
LED2_RED = 3,
LED2_GREEN = 4,
LED2_BLUE = 5,
LED3_RED = 6,
LED3_GREEN = 7,
LED3_BLUE = 8,
;
struct aw9523b_led
struct aw9523b_led_platform_data *pdata;
struct i2c_client *client;
struct rw_semaphore rwsem;
struct work_struct work;
/*
* Making led_classdev as array is not recommended, because array
* members prevent using 'container_of' macro. So repetitive works
* are needed.
*/
struct led_classdev cdev_led1r;
struct led_classdev cdev_led1g;
struct led_classdev cdev_led1b;
struct led_classdev cdev_led2r;
struct led_classdev cdev_led2g;
struct led_classdev cdev_led2b;
struct led_classdev cdev_led3r;
struct led_classdev cdev_led3g;
struct led_classdev cdev_led3b;
enum led_ids led_id;
enum led_colors color;
enum led_brightness brightness;
int reset_gpio;
;
static inline u8 aw9523b_get_base_offset(enum led_ids id, enum led_colors color)
return id * AW9523B_LED_OFFSET + color;
static inline u8 aw9523b_get_reg_addr(enum led_ids id, enum led_colors color,
u8 reg_offset)
return reg_offset + aw9523b_get_base_offset(id, color);
/*--------------------------------------------------------------*/
/* AW9523BGU core functions */
/*--------------------------------------------------------------*/
static int aw9523b_write_byte(struct i2c_client *client, u8 reg, u8 val)
int ret;
mutex_lock(&aw9523b_mutex);
ret = i2c_smbus_write_byte_data(client, reg, val);
if (ret >= 0)
mutex_unlock(&aw9523b_mutex);
return 0;
dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\\n",
__func__, reg, val, ret);
mutex_unlock(&aw9523b_mutex);
return ret;
static int aw9523b_read_byte(struct i2c_client *client, u8 reg, u8 *val)
int ret;
mutex_lock(&aw9523b_mutex);
ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0)
mutex_unlock(&aw9523b_mutex);
return -EIO;
*val = ret;
mutex_unlock(&aw9523b_mutex);
return 0;
static void aw9523b_reset(struct i2c_client *client)
struct aw9523b_led *led = i2c_get_clientdata(client);
/* Configure RESET GPIO (L: RESET, H: RESET cancel) */
gpio_direction_output(led->reset_gpio, 0);
/* Tacss = min 0.1ms */
udelay(20);
gpio_direction_output(led->reset_gpio, 1);
udelay(100);
aw9523b_write_byte(client,0x12,0x00); //OUT4~9配置为呼吸灯模式
aw9523b_write_byte(client,0x12,0x00); //OUT4~9配置为呼吸灯模式
aw9523b_write_byte(client,0x13,0x00); //OUT0~3配置为呼吸灯模式
aw9523b_write_byte(client,0x13,0x00); //OUT0~3配置为呼吸灯模式
static void aw9523b_set_brightness(struct aw9523b_led *led, enum led_ids id,
enum led_colors color, enum led_brightness brightness)
u8 reg;
int ret;
reg = aw9523b_get_reg_addr(id, color, 0x20);
ret = aw9523b_write_byte(led->client, reg, brightness);
if(ret <0)
aw9523b_reset(led->client);
#define AW9523B_SET_REGISTER(reg_addr, reg_name) \\
static ssize_t aw9523b_store_reg##reg_addr(struct device *dev, \\
struct device_attribute *attr, const char *buf, size_t count) \\
\\
struct aw9523b_led *led = i2c_get_clientdata(to_i2c_client(dev));\\
unsigned long val; \\
int ret; \\
if (!count) \\
return -EINVAL; \\
ret = kstrtoul(buf, 16, &val); \\
if (ret) \\
return ret; \\
down_write(&led->rwsem); \\
aw9523b_write_byte(led->client, reg_addr, (u8) val); \\
up_write(&led->rwsem); \\
return count; \\
\\
static struct device_attribute aw9523b_reg##reg_addr##_attr = \\
.attr = .name = reg_name, .mode = 0644, \\
.store = aw9523b_store_reg##reg_addr, \\
;
AW9523B_SET_REGISTER(0x20, "0x20");
AW9523B_SET_REGISTER(0x21, "0x21");
AW9523B_SET_REGISTER(0x22, "0x22");
AW9523B_SET_REGISTER(0x23, "0x23");
AW9523B_SET_REGISTER(0x24, "0x24");
AW9523B_SET_REGISTER(0x25, "0x25");
AW9523B_SET_REGISTER(0x26, "0x26");
AW9523B_SET_REGISTER(0x27, "0x27");
AW9523B_SET_REGISTER(0x28, "0x28");
AW9523B_SET_REGISTER(0x29, "0x29");
AW9523B_SET_REGISTER(0x2a, "0x2a");
AW9523B_SET_REGISTER(0x2b, "0x2b");
AW9523B_SET_REGISTER(0x2c, "0x2c");
AW9523B_SET_REGISTER(0x2d, "0x2d");
AW9523B_SET_REGISTER(0x2e, "0x2e");
AW9523B_SET_REGISTER(0x2f, "0x2f");
static struct device_attribute *aw9523b_addr_attributes[] =
&aw9523b_reg0x20_attr,
&aw9523b_reg0x21_attr,
&aw9523b_reg0x22_attr,
&aw9523b_reg0x23_attr,
&aw9523b_reg0x24_attr,
&aw9523b_reg0x25_attr,
&aw9523b_reg0x26_attr,
&aw9523b_reg0x27_attr,
&aw9523b_reg0x28_attr,
&aw9523b_reg0x29_attr,
&aw9523b_reg0x2a_attr,
&aw9523b_reg0x2b_attr,
&aw9523b_reg0x2c_attr,
&aw9523b_reg0x2d_attr,
&aw9523b_reg0x2e_attr,
&aw9523b_reg0x2f_attr,
;
static void aw9523b_enable_adv_conf(struct aw9523b_led *led)
int i, ret;
for (i = 0; i < ARRAY_SIZE(aw9523b_addr_attributes); i++)
ret = device_create_file(&led->client->dev,
aw9523b_addr_attributes[i]);
if (ret)
dev_err(&led->client->dev, "failed: sysfs file %s\\n",
aw9523b_addr_attributes[i]->attr.name);
goto failed_remove_files;
return;
failed_remove_files:
for (i--; i >= 0; i--)
device_remove_file(&led->client->dev,
aw9523b_addr_attributes[i]);
static void aw9523b_disable_adv_conf(struct aw9523b_led *led)
int i;
for (i = 0; i < ARRAY_SIZE(aw9523b_addr_attributes); i++)
device_remove_file(&led->client->dev,
aw9523b_addr_attributes[i]);
static void aw9523b_led_work(struct work_struct *work)
struct aw9523b_led *led = container_of(work, struct aw9523b_led, work);
//printk("led%d: color = %d,brightness = %d\\n",led->led_id, led->color, led->brightness);
aw9523b_set_brightness(led, led->led_id, led->color, led->brightness);
#define AW9523B_CONTROL_RGBS(name, id, clr) \\
static void aw9523b_set_##name##_brightness(struct led_classdev *led_cdev,\\
enum led_brightness value) \\
\\
struct aw9523b_led *led = \\
container_of(led_cdev, struct aw9523b_led, cdev_##name); \\
led->led_id = id; \\
led->color = clr; \\
led->brightness = value; \\
schedule_work(&led->work); \\
AW9523B_CONTROL_RGBS(led1r, LED1, LED1_RED);
AW9523B_CONTROL_RGBS(led1g, LED1, LED1_GREEN);
AW9523B_CONTROL_RGBS(led1b, LED1, LED1_BLUE);
AW9523B_CONTROL_RGBS(led2r, LED2, LED2_RED);
AW9523B_CONTROL_RGBS(led2g, LED2, LED2_GREEN);
AW9523B_CONTROL_RGBS(led2b, LED2, LED2_BLUE);
AW9523B_CONTROL_RGBS(led3r, LED3, LED3_RED);
AW9523B_CONTROL_RGBS(led3g, LED3, LED3_GREEN);
AW9523B_CONTROL_RGBS(led3b, LED3, LED3_BLUE);
static int aw9523b_register_led_classdev(struct aw9523b_led *led)
int ret;
INIT_WORK(&led->work, aw9523b_led_work);
//led1//
led->cdev_led1r.name = "led1_R";
led->cdev_led1r.brightness = LED_OFF;
led->cdev_led1r.brightness_set = aw9523b_set_led1r_brightness;
ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
if (ret < 0)
dev_err(&led->client->dev, "couldn't register LED %s\\n",
led->cdev_led1r.name);
goto failed_unregister_led1_R;
led->cdev_led1g.name = "led1_G";
led->cdev_led1g.brightness = LED_OFF;
led->cdev_led1g.brightness_set = aw9523b_set_led1g_brightness;
ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
if (ret < 0)
dev_err(&led->client->dev, "couldn't register LED %s\\n",
led->cdev_led1g.name);
goto failed_unregister_led1_G;
led->cdev_led1b.name = "led1_B";
led->cdev_led1b.brightness = LED_OFF;
led->cdev_led1b.brightness_set = aw9523b_set_led1b_brightness;
ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
if (ret < 0)
dev_err(&led->client->dev, "couldn't register LED %s\\n",
led->cdev_led1b.name);
goto failed_unregister_led1_B;
//led2//
led->cdev_led2r.name = "led2_R";
led->cdev_led2r.brightness = LED_OFF;
led->cdev_led2r.brightness_set = aw9523b_set_led2r_brightness;
ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
if (ret < 0)
dev_err(&led->client->dev, "couldn't register LED %s\\n",
led->cdev_led2r.name);
goto failed_unregister_led2_R;
led->cdev_led2g.name = "led2_G";
led->cdev_led2g.brightness = LED_OFF;
led->cdev_led2g.brightness_set = aw9523b_set_led2g_brightness;
ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
if (ret < 0)
dev_err(&led->client->dev, "couldn't register LED %s\\n",
led->cdev_led2g.name);
goto failed_unregister_led2_G;
led->cdev_led2b.name = "led2_B";
led->cdev_led2b.brightness = LED_OFF;
led->cdev_led2b.brightness_set = aw9523b_set_led2b_brightness;
ret = led_classdev_register(&led->client->dev, &led->cdev_led2b);
if (ret < 0)
dev_err(&led->client->dev, "couldn't register LED %s\\n",
led->cdev_led2b.name);
goto failed_unregister_led2_B;
//led3//
led->cdev_led3r.name = "led3_R";
led->cdev_led3r.brightness = LED_OFF;
led->cdev_led3r.brightness_set = aw9523b_set_led3r_brightness;
ret = led_classdev_register(&led->client->dev, &led->cdev_led3r);
if (ret < 0)
dev_err(&led->client->dev, "couldn't register LED %s\\n",
led->cdev_led3r.name);
goto failed_unregister_led3_R;
led->cdev_led3g.name = "led3_G";
led->cdev_led3g.brightness = LED_OFF;
led->cdev_led3g.brightness_set = aw9523b_set_led3g_brightness;
ret = led_classdev_register(&led->client->dev, &led->cdev_led3g);
if (ret < 0)
dev_err(&led->client->dev, "couldn't register LED %s\\n",
led->cdev_led3g.name);
goto failed_unregister_led3_G;
led->cdev_led3b.name = "led3_B";
led->cdev_led3b.brightness = LED_OFF;
led->cdev_led3b.brightness_set = aw9523b_set_led3b_brightness;
ret = led_classdev_register(&led->client->dev, &led->cdev_led3b);
if (ret < 0)
dev_err(&led->client->dev, "couldn't register LED %s\\n",
led->cdev_led3b.name);
goto failed_unregister_led3_B;
return 0;
failed_unregister_led3_B:
led_classdev_unregister(&led->cdev_led3g);
failed_unregister_led3_G:
led_classdev_unregister(&led->cdev_led3r);
failed_unregister_led3_R:
led_classdev_unregister(&led->cdev_led2b);
failed_unregister_led2_B:
led_classdev_unregister(&led->cdev_led2g);
failed_unregister_led2_G:
led_classdev_unregister(&led->cdev_led2r);
failed_unregister_led2_R:
led_classdev_unregister(&led->cdev_led1b);
failed_unregister_led1_B:
led_classdev_unregister(&led->cdev_led1g);
failed_unregister_led1_G:
led_classdev_unregister(&led->cdev_led1r);
failed_unregister_led1_R:
return ret;
static void aw9523b_unregister_led_classdev(struct aw9523b_led *led)
cancel_work_sync(&led->work);
led_classdev_unregister(&led->cdev_led1r);
led_classdev_unregister(&led->cdev_led1g);
led_classdev_unregister(&led->cdev_led1b);
led_classdev_unregister(&led->cdev_led2r);
led_classdev_unregister(&led->cdev_led2g);
led_classdev_unregister(&led->cdev_led2b);
led_classdev_unregister(&led->cdev_led3r);
led_classdev_unregister(&led->cdev_led3g);
led_classdev_unregister(&led->cdev_led3b);
int aw9523b_match_id(struct i2c_client *client)
u8 id = 0;
int tries = 5;
while(tries > 0)
aw9523b_read_byte(client,AW9523B_REG_CHIPID,&id);
printk("read led control chip id: 0x%x\\n", id);
if (id == AW9523B_CHIPID_VALUE)
printk("matched");
return 0;
tries--;
return 1;
static int aw9523b_init(struct aw9523b_led *led)
int ret = 0;
struct i2c_client *client = led->client;
if (led->reset_gpio)
gpio_set_value(led->reset_gpio, 0);
/* Tacss = min 0.1ms */
udelay(20);
gpio_set_value(led->reset_gpio, 1);
udelay(100);
ret = aw9523b_match_id(client);
if(ret)
dev_err(&led->client->dev, "Cannot read chip\\n");
goto out;
aw9523b_write_byte(client,0x12,0x00); //OUT4~9配置为呼吸灯模式
aw9523b_write_byte(client,0x12,0x00); //OUT4~9配置为呼吸灯模式
aw9523b_write_byte(client,0x13,0x00); //OUT0~3配置为呼吸灯模式
aw9523b_write_byte(client,0x13,0x00); //OUT0~3配置为呼吸灯模式
return 0;
out:
if (ret)
if (led->reset_gpio)
gpio_set_value(led->reset_gpio, 0);
return ret;
static int aw9523b_probe(struct i2c_client *client,
const struct i2c_device_id *id)
int ret;
struct aw9523b_led *led;
int gpio = 0;
printk("%s:enter\\n",__FUNCTION__);
mutex_init(&aw9523b_mutex);
led = kzalloc(sizeof(struct aw9523b_led), GFP_KERNEL);
if (!led)
dev_err(&client->dev, "failed to allocate driver data\\n");
return -ENOMEM;
if (client->dev.of_node)
/* Get GPIO from device tree */
gpio = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);
if (gpio < 0)
dev_err(&client->dev,
"Failed to retrieve reset-gpios from device tree\\n");
return gpio;
/* GPIO request and configuration */
ret = devm_gpio_request_one(&client->dev, gpio,
GPIOF_OUT_INIT_HIGH, "aw9523b_reset");
if (ret)
dev_err(&client->dev, "Failed to request reset pin\\n");
goto failed_free;
led->reset_gpio = gpio;
led->client = client;
init_rwsem(&led->rwsem);
i2c_set_clientdata(client, led);
ret = aw9523b_init(led);
if (ret)
goto failed_free;
ret = aw9523b_register_led_classdev(led);
if (ret)
dev_err(&client->dev, "led register err: %d\\n", ret);
goto failed_free;
//aw9523b_enable_adv_conf(led);
printk("%s:exit\\n",__FUNCTION__);
return 0;
failed_free:
kfree(led);
return ret;
static int aw9523b_remove(struct i2c_client *client)
struct aw9523b_led *led = i2c_get_clientdata(client);
gpio_set_value(led->reset_gpio, 0);
aw9523b_unregister_led_classdev(led);
//aw9523b_disable_adv_conf(led);
kfree(led);
return 0;
static const struct i2c_device_id aw9523b_id[] =
"aw9523b", 0 ,
;
MODULE_DEVICE_TABLE(i2c, aw9523b_id);
#ifdef CONFIG_OF
static const struct of_device_id of_aw9523b_leds_match[] =
.compatible = "xxx,aw9523b-leds", ,
,
;
MODULE_DEVICE_TABLE(of, of_aw9523b_leds_match);
#endif
static struct i2c_driver aw9523b_driver =
.driver =
.name = "aw9523b",
.of_match_table = of_match_ptr(of_aw9523b_leds_match),
,
.probe = aw9523b_probe,
.remove = aw9523b_remove,
.id_table = aw9523b_id,
;
module_i2c_driver(aw9523b_driver);
MODULE_DESCRIPTION("AW9523B LED driver");
MODULE_AUTHOR("Thornton Wu <447116230@qq.com>");
MODULE_LICENSE("GPL");
linux\\drivers\\leds\\Makefile
obj-m += leds-aw9523b.o
2 KERNEL编译
export PATH=$PATH:/home/thornton/work/pi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=/home/thornton/work/pi/firmware modules_install
3 KERNEL更新
将RPI T卡插在LINUX系统下,会弹出两个盘,一个是KERENL盘和一个BOOT盘
将firmware/lib拷到KERNEL盘,其他拷到BOOT盘
4 启动驱动
/boot/config.txt
dtoverlay=example-leds
/etc/ modules
leds-aw9523b
/etc/udev/rules.d/ 99-com.rules
SUBSYSTEM=="leds", PROGRAM="/bin/sh -c '\\
chmod 666 /sys/class/leds/led1_R/brightness;\\
chmod 666 /sys/class/leds/led1_G/brightness;\\
chmod 666 /sys/class/leds/led1_B/brightness;\\
chmod 666 /sys/class/leds/led2_R/brightness;\\
chmod 666 /sys/class/leds/led2_G/brightness;\\
chmod 666 /sys/class/leds/led2_B/brightness;\\
chmod 666 /sys/class/leds/led3_R/brightness;\\
chmod 666 /sys/class/leds/led3_G/brightness;\\
chmod 666 /sys/class/leds/led3_B/brightness;\\
'"
以上是关于树莓派-LED篇的主要内容,如果未能解决你的问题,请参考以下文章