安霸平台led芯片aw9523b调试

公司的车载项目用到了一颗艾为的led芯片驱动16路led,下面描述一下调试过程
硬件原理图如下
在这里插入图片描述
aw9523 驱动采用led驱动框架,比较简单,调用内核API直接注册进led子系统可以了,下面是dts配置

i2c3: i2c@e400b000 {
	 aw9523@5B{
                                compatible = "awinic,aw9523_led";
                                reg = <0x5B>;
                                aw9523_reset-gpios = <&gpio 36 0>;
                                aw9523,gps_led_green {
                                    aw9523,name = "gps_green";
                                    aw9523,id = <0>;
                                    aw9523,max-brightness = <255>;
                                };
                                aw9523,gps_led_red {
                                    aw9523,name = "gps_red";
                                    aw9523,id = <1>;
                                    aw9523,max-brightness = <255>;
                                };

                                aw9523,wifi_led_green {
                                    aw9523,name = "wifi_green";
                                    aw9523,id = <2>;
                                    aw9523,max-brightness = <255>;
                                };
                                aw9523,wifi_led_red {
                                    aw9523,name = "wifi_red";
                                    aw9523,id = <3>;
                                    aw9523,max-brightness = <255>;
                                };

                                aw9523,notification_led_blue {
                                    aw9523,name = "noti_blue";
                                    aw9523,id = <4>;
                                    aw9523,max-brightness = <255>;
                                };
                                aw9523,notification_led_green {
                                    aw9523,name = "noti_green";
                                    aw9523,id = <5>;
                                    aw9523,max-brightness = <255>;
                                };i2c3: i2c@e400b000 {
                                aw9523,notification_led_red {
                                    aw9523,name = "noti_red";
                                    aw9523,id = <6>;
                                    aw9523,max-brightness = <255>;
                                };
                                aw9523,eld_led_blue {
                                    aw9523,name = "eld_blue";
                                    aw9523,id = <7>;
                                    aw9523,max-brightness = <255>;
                                };
                                aw9523,eld_led_green {
                                    aw9523,name = "eld_green";
                                    aw9523,id = <8>;
                                    aw9523,max-brightness = <255>;
                                };
                                aw9523,eld_led_red {
                                    aw9523,name = "eld_red";
                                    aw9523,id = <9>;
                                    aw9523,max-brightness = <255>;
                                };

                                aw9523,bt_led_green {
                                    aw9523,name = "bt_green";
                                    aw9523,id = <12>;
                                    aw9523,max-brightness = <255>;
                                };
                                aw9523,bt_led_red {
                                    aw9523,name = "bt_red";
                                    aw9523,id = <13>;
                                    aw9523,max-brightness = <255>;
                                };
                                aw9523,cell_led_green {
                                    aw9523,name = "cell_green";
                                    aw9523,id = <14>;
                                    aw9523,max-brightness = <255>;
                                };
                                aw9523,cell_led_red {
                                    aw9523,name = "cell_red";
                                    aw9523,id = <15>;
                                    aw9523,max-brightness = <255>;
                                };

};

下面是驱动源码

/*
 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
 *
 * Version: v1.0.0
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/gpio/consumer.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/leds-aw9523.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>

/* aw9523 register */
#define AW9523_REG_CHIPID		0x10
#define AW9523_LED_MODE_P0		0x12
#define AW9523_LED_MODE_P1		0x13
#define AW9523_LED_MODE			0x00
#define AW9523_CHIPID			0x23
#define AW9523_REG_MAX			0x7F
#define AW9523_REG_BRIGHTNESS_BASE		0x20

struct aw9523_led {
	struct i2c_client *client;
	struct led_classdev cdev;
	struct work_struct brightness_work;
	struct aw9523_platform_data *pdata;
	struct mutex lock;
	int num_leds;
	int id;
	int reset_gpio;
};

static int aw9523_write(struct aw9523_led *led, u8 reg, u8 val)
{
	int ret = -EINVAL, retry_times = 0;

	do {
		ret = i2c_smbus_write_byte_data(led->client, reg, val);
		retry_times ++;
		if(retry_times == 5)
			break;
	}while (ret < 0);
	
	return ret;	
}

static int aw9523_read(struct aw9523_led *led, u8 reg, u8 *val)
{
	int ret = -EINVAL, retry_times = 0;

	do{
		ret = i2c_smbus_read_byte_data(led->client, reg);
		retry_times ++;
		if(retry_times == 5)
			break;
	}while (ret < 0);
	if (ret < 0)
		return ret;

	*val = ret;
	return 0;
}

static void aw9523_brightness_work(struct work_struct *work)
{
	struct aw9523_led *led = container_of(work, struct aw9523_led,
					brightness_work);
					
	mutex_lock(&led->pdata->led->lock);

	dev_err(&led->client->dev,
			"%s:enter, id = %d name = %s, brightness = %d\n",__func__,led->id,led->cdev.name,led->cdev.brightness);
	
	if (led->cdev.brightness >= 0) {
		if (led->cdev.brightness > led->cdev.max_brightness)
			led->cdev.brightness = led->cdev.max_brightness;
			
		aw9523_write(led, AW9523_REG_BRIGHTNESS_BASE + led->id, led->cdev.brightness); 
	}else{
			dev_err(&led->client->dev,
				"brightness is fault, set brightness fail\n");
	}
	mutex_unlock(&led->pdata->led->lock);
}

static void aw9523_set_brightness(struct led_classdev *cdev,
			     enum led_brightness brightness)
{
	struct aw9523_led *led = container_of(cdev, struct aw9523_led, cdev);

	led->cdev.brightness = brightness;

	schedule_work(&led->brightness_work);
}



static ssize_t aw9523_reg_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
	struct aw9523_led *led =
			container_of(led_cdev, struct aw9523_led, cdev);

	unsigned char i, reg_val;
	ssize_t len = 0;

    for(i=0; i<AW9523_REG_MAX; i++) {
        aw9523_read(led, i, &reg_val);
        len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x\n", i, reg_val);
    }

	return len;
}

static ssize_t aw9523_reg_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t len)
{
	struct led_classdev *led_cdev = dev_get_drvdata(dev);
	struct aw9523_led *led =
			container_of(led_cdev, struct aw9523_led, cdev);

	unsigned int databuf[2];

	if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1]))
	{
		aw9523_write(led, (unsigned char)databuf[0], (unsigned char)databuf[1]);
	}

	return len;
}

static DEVICE_ATTR(reg, 0664, aw9523_reg_show, aw9523_reg_store);

static struct attribute *aw9523_led_attributes[] = {
	&dev_attr_reg.attr,
	NULL,
};

static struct attribute_group aw9523_led_attr_group = {
	.attrs = aw9523_led_attributes
};

static int aw9523_check_chipid(struct aw9523_led *led)
{
	u8 val;
	u8 cnt;

	for(cnt = 5; cnt > 0; cnt --)
	{
		aw9523_read(led, AW9523_REG_CHIPID, &val);
		dev_err(&led->client->dev,"aw9523 chip id %0x",val);
		if (val == AW9523_CHIPID)
			return 0;
	}
		return -EINVAL;
}

static int aw9523_led_err_handle(struct aw9523_led *led_array,
				int parsed_leds)
{
	int i;
	/*
	 * If probe fails, cannot free resource of all LEDs, only free
	 * resources of LEDs which have allocated these resource really.
	 */
	for (i = 0; i < parsed_leds; i++) {
		sysfs_remove_group(&led_array[i].cdev.dev->kobj,
				&aw9523_led_attr_group);
		led_classdev_unregister(&led_array[i].cdev);
		cancel_work_sync(&led_array[i].brightness_work);
		devm_kfree(&led_array->client->dev, led_array[i].pdata);
		led_array[i].pdata = NULL;
	}
	return i;
}

static void switch_to_led_mode(struct aw9523_led *led)
{
	aw9523_write(led, AW9523_LED_MODE_P0, AW9523_LED_MODE);
	aw9523_write(led, AW9523_LED_MODE_P1, AW9523_LED_MODE);
}
static int aw9523_led_parse_child_node(struct aw9523_led *led_array,
				struct device_node *node)
{
	struct aw9523_led *led;
	struct device_node *temp;
	struct aw9523_platform_data *pdata;
	int rc = 0, parsed_leds = 0;

	for_each_child_of_node(node, temp) {
		led = &led_array[parsed_leds];
		led->client = led_array->client;

		pdata = devm_kzalloc(&led->client->dev,
				sizeof(struct aw9523_platform_data),
				GFP_KERNEL);
		if (!pdata) {
			dev_err(&led->client->dev,
				"Failed to allocate memory\n");
			goto free_err;
		}
		pdata->led = led_array;
		led->pdata = pdata;

		rc = of_property_read_string(temp, "aw9523,name",
			&led->cdev.name);
		if (rc < 0) {
			dev_err(&led->client->dev,
				"Failure reading led name, rc = %d\n", rc);
			goto free_pdata;
		}

		rc = of_property_read_u32(temp, "aw9523,id",
			&led->id);
		if (rc < 0) {
			dev_err(&led->client->dev,
				"Failure reading id, rc = %d\n", rc);
			goto free_pdata;
		}
		

		rc = of_property_read_u32(temp, "aw9523,max-brightness",
			&led->cdev.max_brightness);
		if (rc < 0) {
			dev_err(&led->client->dev,
				"Failure reading max-brightness, rc = %d\n",
				rc);
			goto free_pdata;
		}

		
		INIT_WORK(&led->brightness_work, aw9523_brightness_work);

		led->cdev.brightness_set = aw9523_set_brightness;
//注册进led子系统
		rc = led_classdev_register(&led->client->dev, &led->cdev);
		if (rc) {
			dev_err(&led->client->dev,
				"unable to register led %d,rc=%d\n",
				led->id, rc);
			goto free_pdata;
		}

		rc = sysfs_create_group(&led->cdev.dev->kobj,
				&aw9523_led_attr_group);
		if (rc) {
			dev_err(&led->client->dev, "led sysfs rc: %d\n", rc);
			goto free_class;
		}
		parsed_leds++;
	}

	
	return 0;

free_class:
	aw9523_led_err_handle(led_array, parsed_leds);
	led_classdev_unregister(&led_array[parsed_leds].cdev);
	cancel_work_sync(&led_array[parsed_leds].brightness_work);
	devm_kfree(&led->client->dev, led_array[parsed_leds].pdata);
	led_array[parsed_leds].pdata = NULL;
	return rc;

free_pdata:
	aw9523_led_err_handle(led_array, parsed_leds);
	devm_kfree(&led->client->dev, led_array[parsed_leds].pdata);
	return rc;

free_err:
	aw9523_led_err_handle(led_array, parsed_leds);
	return rc;
}

static int aw9523_led_probe(struct i2c_client *client,
			   const struct i2c_device_id *id)
{
	struct aw9523_led *led_array;
	struct device_node *node;
	int ret, num_leds = 0;
	enum of_gpio_flags flags;
	node = client->dev.of_node;
	if (node == NULL)
		return -EINVAL;

	num_leds = of_get_child_count(node);

	if (!num_leds)
		return -EINVAL;

	led_array = devm_kzalloc(&client->dev,
			(sizeof(struct aw9523_led) * num_leds), GFP_KERNEL);
	if (!led_array)
		return -ENOMEM;

	led_array->client = client;
	led_array->num_leds = num_leds;

	mutex_init(&led_array->lock);

    //解析dts中内容
	ret = aw9523_led_parse_child_node(led_array, node);
	if (ret) {
		dev_err(&client->dev, "parsed node error\n");
		goto free_led_arry;
	}
	led_array->reset_gpio = of_get_named_gpio_flags(node, "aw9523_reset-gpios", 0, &flags);
        if (gpio_is_valid(led_array->reset_gpio)) {

                ret = devm_gpio_request(&client->dev, led_array->reset_gpio, "aw9523_led_reset");
                if (ret < 0){
                        dev_err(&client->dev, "Failed to request reset_pin: %d\n", ret);
                        return ret;
                }
        	gpio_direction_output(led_array->reset_gpio,1);
		msleep(20);
		gpio_direction_output(led_array->reset_gpio,0);
		msleep(20);
		gpio_direction_output(led_array->reset_gpio,1);
		msleep(20);
		dev_err(&client->dev, "get  reset gpio sucess,%d\n",led_array->reset_gpio);

        }else {
		dev_err(&client->dev, "get  reset gpio fail,%d\n",led_array->reset_gpio);
        }
	i2c_set_clientdata(client, led_array);
	ret = aw9523_check_chipid(led_array);
	if (ret) {
		dev_err(&client->dev, "Check chip id error\n");
		goto fail_parsed_node;
	}
//aw9523有两种模式,gpio和led模式,切换到led模式
	switch_to_led_mode(led_array);
	dev_err(&client->dev, "aw9523_led_probe sucess\n");
	return 0;

fail_parsed_node:
	aw9523_led_err_handle(led_array, num_leds);
free_led_arry:
	mutex_destroy(&led_array->lock);
	devm_kfree(&client->dev, led_array);
	led_array = NULL;
	return ret;
}

static int aw9523_led_remove(struct i2c_client *client)
{
	struct aw9523_led *led_array = i2c_get_clientdata(client);
	int i, parsed_leds = led_array->num_leds;

	for (i = 0; i < parsed_leds; i++) {
		sysfs_remove_group(&led_array[i].cdev.dev->kobj,
				&aw9523_led_attr_group);
		led_classdev_unregister(&led_array[i].cdev);
		cancel_work_sync(&led_array[i].brightness_work);
		devm_kfree(&client->dev, led_array[i].pdata);
		led_array[i].pdata = NULL;
	}
	mutex_destroy(&led_array->lock);
	devm_kfree(&client->dev, led_array);
	led_array = NULL;
	return 0;
}

static const struct i2c_device_id aw9523_led_id[] = {
	{"aw9523_led", 0},
	{},
};

MODULE_DEVICE_TABLE(i2c, aw9523_led_id);

static struct of_device_id aw9523_match_table[] = {
	{ .compatible = "awinic,aw9523_led",},
	{ },
};

static struct i2c_driver aw9523_led_driver = {
	.probe = aw9523_led_probe,
	.remove = aw9523_led_remove,
	.driver = {
		.name = "aw9523_led",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(aw9523_match_table),
	},
	.id_table = aw9523_led_id,
};

static int __init aw9523_led_init(void)
{
	return i2c_add_driver(&aw9523_led_driver);
}
module_init(aw9523_led_init);

static void __exit aw9523_led_exit(void)
{
	i2c_del_driver(&aw9523_led_driver);
}
module_exit(aw9523_led_exit);

MODULE_AUTHOR("<chengbingbing");
MODULE_DESCRIPTION("AWINIC AW9523 LED driver");
MODULE_LICENSE("GPL v2");

leds-aw9523.h中内容

#ifndef __LINUX_AW9523_LED_H__
#define __LINUX_AW9523_LED_H__

/* The definition of each time described as shown in figure.
 *        /-----------\
 *       /      |      \
 *      /|      |      |\
 *     / |      |      | \-----------
 *       |hold_time_ms |      |
 *       |             |      |
 * rise_time_ms  fall_time_ms |
 *                       off_time_ms
 */

struct aw9523_platform_data {
        int imax;
        int led_current;
        int rise_time_ms;
        int hold_time_ms;
        int fall_time_ms;
        int off_time_ms;
        struct aw9523_led *led;
};

#endif
~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值