安霸平台gpio扩展芯片aw9523b调试

公司的一个车载项目由于gpio扣较少,所以用了艾为的一颗16路gpio口扩展芯片,下面描述一下调试过程
硬件原理图如下
在这里插入图片描述
aw9523b芯片寄存器较少,直接自己写了个简单的gpio驱动,采用gpio子系统驱动,比较简单,下面是dts配置以及驱动源码

dts配置
 aw9523: aw9523@58 {
                                compatible = "awinic,aw9523_gpio";
                                aw9523_reset-gpios = <&gpio 82 0>;
                                reg = <0x58>;
                                gpio-controller;
                                interrupt-parent = <&gpio>;
                                interrupt-controller;
                                #gpio-cells = <2>;
                                interrupts = <14 0x0>;
                        };

驱动源码
// SPDX-License-Identifier: GPL-2.0+
/*
 * gpiolib support for Wolfson WM835x PMICs
 *
 * Copyright 2009 Wolfson Microelectronics PLC.
 *
 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
 *
 */

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/gpio/driver.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/leds.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>

/* 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_gpio {
	int aw9523_init_finished;
	int reset_gpio;
	struct gpio_desc *aw9523_rst_gpio;
	struct i2c_client *aw9523_client;
	struct gpio_chip aw9523_gpio_chip;
	struct device dev;
	spinlock_t lock;
};

static u8 reg_read(struct aw9523_gpio *aw9523_gpio_dev, u8 reg)
{
        u8 buf;
        int ret;
        struct i2c_msg msgs[] = {
                {
                        .addr  = aw9523_gpio_dev->aw9523_client->addr,
                        .flags = 0,
                        .len   = 1,
                        .buf   = &reg,
                }, {
                        .addr  = aw9523_gpio_dev->aw9523_client->addr,
                        .flags = I2C_M_RD,
                        .len   = 1,
                        .buf   = &buf,
                },
        };

        ret = i2c_transfer(aw9523_gpio_dev->aw9523_client->adapter, msgs, ARRAY_SIZE(msgs));
        if (ret < 0) {
                dev_err(&aw9523_gpio_dev->aw9523_client->dev, "aw9523 Reading register %x from %x failed\n",
                         reg, aw9523_gpio_dev->aw9523_client->addr);
                return ret;
        }

        return buf;
}

static int aw9523_read_reg(struct aw9523_gpio *aw9523_gpio_dev, u8 reg)
{
	int rc;

	rc = reg_read(aw9523_gpio_dev,reg);
	
		dev_err(&aw9523_gpio_dev->aw9523_client->dev,"aw9523 read reg = %02x, value = %02x****\n",reg,rc);
	rc = i2c_smbus_read_byte_data(aw9523_gpio_dev->aw9523_client, reg);
	if (rc < 0) {
		dev_err(&aw9523_gpio_dev->aw9523_client->dev,
			"<%s> can't read from %02x, i2c addr= %02x\n", __func__, reg, aw9523_gpio_dev->aw9523_client->addr);
		return -rc;
	}
	return rc;
}

static int aw9523_write_reg(struct aw9523_gpio *aw9523_gpio_dev, u8 reg, u8 val)
{
	int rc;

	rc = i2c_smbus_write_byte_data(aw9523_gpio_dev->aw9523_client, reg,
				       val);
	if (rc < 0) {
		dev_err(&aw9523_gpio_dev->aw9523_client->dev,
			"<%s> can't write %02x to %02x\n", __func__, val, reg);
		return -rc;
	}
	return 0;
}

static int aw9523_check_chipid(struct aw9523_gpio *aw9523_gpio_dev)
{
	u8 val;
	u8 cnt;

	for (cnt = 5; cnt > 0; cnt--) {
		val = aw9523_read_reg(aw9523_gpio_dev, AW9523_REG_CHIPID);
		dev_err(&aw9523_gpio_dev->aw9523_client->dev,
			"<%s> aw9523 chip id %0x\n", __func__, val);
		if (val == AW9523_CHIPID)
			return 0;
	}
	return -EINVAL;
}
int aw9523_gpio_get_value(struct aw9523_gpio *aw9523_gpio_dev, int port)
{
	u8 val;
	int value;

	if (aw9523_gpio_dev->aw9523_init_finished == 0) {
		dev_err(&aw9523_gpio_dev->aw9523_client->dev,
			"<%s> aw9523 is not inited\n", __func__);
		return -EPERM;
	}

	if (port < 0 || port > 15) {
		dev_err(&aw9523_gpio_dev->aw9523_client->dev,
			"<%s> invalid port: %d\n", __func__, port);
		return -EINVAL;
	}

	if (value != 0 && value != 1) {
		dev_err(&aw9523_gpio_dev->aw9523_client->dev,
			"<%s> invalid value\n", __func__);
		return -EINVAL;
	}

	val = (u8)aw9523_read_reg(aw9523_gpio_dev, 0x02 + port / 8);
	value = (val >> port) & 1;
	return value;
}

int aw9523_gpio_set_value(struct aw9523_gpio *aw9523_gpio_dev, int port,
			  int value)
{
	u8 val;

	if (aw9523_gpio_dev->aw9523_init_finished == 0) {
		dev_err(&aw9523_gpio_dev->aw9523_client->dev,
			"<%s> aw9523 is not inited\n", __func__);
		return -EPERM;
	}

	if (port < 0 || port > 15) {
		dev_err(&aw9523_gpio_dev->aw9523_client->dev,
			"<%s> invalid port: %d\n", __func__, port);
		return -EINVAL;
	}

	if (value != 0 && value != 1) {
		dev_err(&aw9523_gpio_dev->aw9523_client->dev,
			"<%s> invalid value\n", __func__);
		return -EINVAL;
	}

//	val = (u8)aw9523_read_reg(aw9523_gpio_dev, 0x02 + port / 8);

	if (value == 0)
		val &= ~(1 << (port % 8));
	else
		val |= 1 << (port % 8);

		dev_err(&aw9523_gpio_dev->aw9523_client->dev,
			"<%s> begin to write reg\n", __func__);

	return aw9523_write_reg(aw9523_gpio_dev, 0x02 + port / 8, val);
}

static int aw9523_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
	int value;
	unsigned long flags;
	struct aw9523_gpio *aw9523_gpio_dev =
		container_of(chip, struct aw9523_gpio, aw9523_gpio_chip);

	spin_lock_irqsave(&aw9523_gpio_dev->lock, flags);
	value = aw9523_gpio_get_value(aw9523_gpio_dev, offset);
	spin_unlock_irqrestore(&aw9523_gpio_dev->lock, flags);

	return value;
}


static void aw9523_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
	unsigned long flags;
	struct aw9523_gpio *aw9523_gpio_dev =
		container_of(chip, struct aw9523_gpio, aw9523_gpio_chip);
	spin_lock_irqsave(&aw9523_gpio_dev->lock, flags);
	aw9523_gpio_set_value(aw9523_gpio_dev, offset, value);
	spin_unlock_irqrestore(&aw9523_gpio_dev->lock, flags);
}

static int aw9523_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
				     int value)
{
	unsigned long flags;

	struct aw9523_gpio *aw9523_gpio_dev =
		container_of(chip, struct aw9523_gpio, aw9523_gpio_chip);

	spin_lock_irqsave(&aw9523_gpio_dev->lock, flags);
	dev_err(&aw9523_gpio_dev->aw9523_client->dev,
		"%s:offset = %d,value = %d\n", __func__, offset, value);

	aw9523_gpio_set_value(aw9523_gpio_dev, offset, value);
	spin_unlock_irqrestore(&aw9523_gpio_dev->lock, flags);
	return 0;
}

static ssize_t aw9523_gpio_store(struct device *dev,
               struct device_attribute *attr, const char *buf, size_t count)
{
       int rc;
       int port;
       int value;
       char port_buf[5];
       char value_buf[5];

       struct i2c_client *client =
                container_of(dev, struct i2c_client, dev);
       struct aw9523_gpio *aw9523_gpio_dev =
                i2c_get_clientdata(client);

       if (count < 2) {
               pr_err("<%s> invalid write string: %s\n", __func__, buf);
               return -EINVAL;
       }
       sscanf(buf,"%s %s",port_buf,value_buf);
       rc = kstrtouint(port_buf, 10, &port);
       rc = kstrtouint(value_buf, 10, &value);
	
       dev_err(dev, "%s:bing port = %d value = %d addr = %02x\n",__func__,port,value,aw9523_gpio_dev->aw9523_client->addr);
       rc = aw9523_gpio_set_value(aw9523_gpio_dev, port, value);
       return (rc == 0) ? count : -EINVAL;
}


static DEVICE_ATTR(aw9523_gpio, S_IWUSR | S_IWGRP, NULL, aw9523_gpio_store);

static int aw9523_gpio_probe(struct i2c_client *client,
			     const struct i2c_device_id *id)
{
	int ret;
	enum of_gpio_flags flags;
	int i;
	struct aw9523_gpio *aw9523_gpio_dev;
	
	aw9523_gpio_dev = devm_kzalloc(
		&client->dev, (sizeof(struct aw9523_gpio)), GFP_KERNEL);
	if (!aw9523_gpio_dev)
		return -ENOMEM;

	aw9523_gpio_dev->aw9523_client = client;
	aw9523_gpio_dev->aw9523_rst_gpio =
		devm_gpiod_get_optional(&client->dev, "aw9523_reset", 0);
	if (!aw9523_gpio_dev->aw9523_rst_gpio) {
		dev_err(&client->dev, "invalid  reset gpio\n");
		return -1;
	} else {
		gpiod_direction_output(aw9523_gpio_dev->aw9523_rst_gpio, 1);
		msleep(20);
		gpiod_direction_output(aw9523_gpio_dev->aw9523_rst_gpio, 0);
		msleep(30);
		gpiod_direction_output(aw9523_gpio_dev->aw9523_rst_gpio, 1);
		msleep(20);
	}

	aw9523_gpio_dev->aw9523_gpio_chip.label = "aw9523_gpio";
	aw9523_gpio_dev->aw9523_gpio_chip.owner = THIS_MODULE;
	aw9523_gpio_dev->aw9523_gpio_chip.direction_output =
		aw9523_gpio_direction_out;
	aw9523_gpio_dev->aw9523_gpio_chip.set = aw9523_gpio_set;
	aw9523_gpio_dev->aw9523_gpio_chip.get = aw9523_gpio_get;
	aw9523_gpio_dev->aw9523_gpio_chip.ngpio = 16;
	aw9523_gpio_dev->aw9523_gpio_chip.parent = &client->dev;
	aw9523_gpio_dev->aw9523_gpio_chip.base = -1;

	ret = devm_gpiochip_add_data(&client->dev,
				     &(aw9523_gpio_dev->aw9523_gpio_chip),
				     &(aw9523_gpio_dev->aw9523_gpio_chip));
	if (ret) {
		dev_err(&client->dev, "devm_gpiochip_add_data error\n");
		return -EINVAL;
	}

	ret = aw9523_check_chipid(aw9523_gpio_dev);
	if (ret) {
		dev_err(&client->dev, "Check chip id error\n");
		return -EINVAL;
	}
	// set P0 port as push-pull mode
	aw9523_write_reg(aw9523_gpio_dev, 0x11, 0x10);
	aw9523_write_reg(aw9523_gpio_dev, 0x12, 0xff);
	aw9523_write_reg(aw9523_gpio_dev, 0x13, 0xff);
	// P0 and P1 port output mode
	aw9523_write_reg(aw9523_gpio_dev, 0x04, 0x00);
	aw9523_write_reg(aw9523_gpio_dev, 0x05, 0x00);
	// disable interrupt function of P0 and P1 port
	aw9523_write_reg(aw9523_gpio_dev, 0x06, 0xff);
	aw9523_write_reg(aw9523_gpio_dev, 0x07, 0xff);
	// P0 and P1 port output low level
	aw9523_write_reg(aw9523_gpio_dev, 0x02, 0x00);
	aw9523_write_reg(aw9523_gpio_dev, 0x03, 0x00);

	
	spin_lock_init(&aw9523_gpio_dev->lock);
	aw9523_gpio_dev->aw9523_init_finished = 1;
	i2c_set_clientdata(client, aw9523_gpio_dev);
	
	ret = device_create_file(&client->dev, &dev_attr_aw9523_gpio);
        if (ret) {
               pr_err("<%s> create file aw9523_gpio failed\n", __func__);
               return -EPERM;
        }

	dev_err(&client->dev, "aw9523_probe succeeded\n");

	return 0;
}

static int aw9523_gpio_remove(struct i2c_client *client)
{
	return 0;
}

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

static const struct i2c_device_id aw9523_id[] = {
	{ "awinic,aw9523_gpio", 0 },
	{},
};
MODULE_DEVICE_TABLE(i2c, aw9523_id);

static struct i2c_driver aw9523_driver = {
	.driver = {
		.name = "aw9523-gpio",
		.owner		= THIS_MODULE,
		.of_match_table = aw9523_match_table,
	},
	.probe    = aw9523_gpio_probe,
	.remove   = aw9523_gpio_remove,
	.id_table = aw9523_id,
};

module_i2c_driver(aw9523_driver);
MODULE_LICENSE("GPL V2");

```c
在这里插入代码片


  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值