uboot aw9523 gpio expander driver

接上一篇aw9523驱动,由于板卡上的lcm的上电需要使用到aw9523扩展出来的gpio,而开机logo需要在uboot就开始显示,则需要在uboot中实现aw9523的DM模型的驱动

关于DM模型可以参考 超详细【Uboot驱动开发】(三)Uboot驱动模型uboot 驱动模型

这边文章仅描述aw9523 在uboot中的过程

/*
 * (C) Copyright 2020 Rockchip Electronics Co., Ltd
 *
 * SPDX-License-Identifier:     GPL-2.0+
 */

#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <asm/gpio.h>

struct dm_aw9523_ops {
	int (*get_value)(unsigned int offset);
	void (*set_value)(unsigned int offset, int value);
};

struct aw9523_gpio {
	struct udevice *dev;
	struct gpio_desc reset_gpio;
};

static struct aw9523_gpio *aw9523_client = NULL;
/* 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

int aw9523_i2c_write(struct aw9523_gpio *aw9523_gpio, u8 reg, u8 val)
{
	int ret;
	u8 buf[2];
	struct i2c_msg msg;
	struct dm_i2c_chip *chip = dev_get_parent_platdata(aw9523_gpio->dev);

	buf[0] = reg;
	buf[1] = val;
	msg.addr = chip->chip_addr;
	msg.flags = 0;
	msg.len = 2;
	msg.buf = buf;

	ret = dm_i2c_xfer(aw9523_gpio->dev, &msg, 1);
	if (ret) {
		printf("aw9523 i2c write failed: %d\n", ret);
		return ret;
	}

	return 0;
}

int aw9523_i2c_read(struct aw9523_gpio *aw9523_gpio, u8 reg, u8 *val)
{
	int ret;
	u8 data;
	struct dm_i2c_chip *chip = dev_get_parent_platdata(aw9523_gpio->dev);
	struct i2c_msg msg[] = {
		{
			.addr = chip->chip_addr,
			.flags = 0,
			.buf = (u8 *)&reg,
			.len = 1,
		}, {
			.addr = chip->chip_addr,
			.flags = I2C_M_RD,
			.buf = (u8 *)&data,
			.len = 1,
		}
	};

	ret = dm_i2c_xfer(aw9523_gpio->dev, msg, 2);
	if (ret) {
		printf("aw9523 i2c read failed: %d\n", ret);
		return ret;
	}

	*val = data;

	return 0;
}

static int aw9523_get_value(struct udevice *dev, int port)
{
	int ret;
	u8 data;
	int value;
	struct aw9523_gpio *gpios = dev_get_priv(dev);

	if (port < 0 || port > 15) {
		printf("<%s> invalid port: %d\n", __func__, port);
		return -EINVAL;
	}
	
	ret = (u8)aw9523_i2c_read(gpios, 0x02 + port / 8, &data);
	if(ret)
	{
		return -1;
	}
	value = (data >> port) & 1;
	printf("====>reg %x  value %x\n", 0x02 + port / 8, value);
	return value;
}

static int aw9523_set_value(struct udevice *dev, int port,
				  int value)
{
	int ret;
	u8 val;
	struct aw9523_gpio *gpios = dev_get_priv(dev);
	
	if (port < 0 || port > 15) {
		printf("<%s> invalid port: %d\n", __func__, port);
		return -1;
	}

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

	ret = (u8)aw9523_i2c_read(gpios, 0x02 + port / 8, &val);

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

	ret = aw9523_i2c_write(gpios, port, value);
	if(ret)
	{
		printf("aw9523 i2c write failed: %d\n", ret);
		return ret;
	}

	return 0;
}

int aw9523_port_get(unsigned int offset)
{
	int value;
	if(aw9523_client)
	{
		value = aw9523_get_value(aw9523_client->dev, offset);
		return value;
	}
	return 0;
}

void aw9523_port_set(unsigned int offset, int value)
{
	if(aw9523_client)
	{
		aw9523_set_value(aw9523_client->dev, offset, value);
	}
}

static const struct dm_aw9523_ops aw9523_gpio_ops = {
	.get_value		= aw9523_port_get,
	.set_value		= aw9523_port_set,
};

static int aw9523_probe(struct udevice *dev)
{
	int ret;
	struct aw9523_gpio *aw9523_gpio = dev_get_priv(dev);

	aw9523_client = aw9523_gpio;
	aw9523_gpio->dev = dev;

	ret = gpio_request_by_name(dev, "aw9523_reset-gpios", 0,
				   &aw9523_gpio->reset_gpio, GPIOD_IS_OUT);
	if (ret) {
		printf("Cannot get wakeup_pin GPIO: %d\n", ret);
		return ret;
	}
	
	if (dm_gpio_is_valid(&aw9523_gpio->reset_gpio))
	{
		dm_gpio_set_value(&aw9523_gpio->reset_gpio, 1);
		mdelay(20);
		dm_gpio_set_value(&aw9523_gpio->reset_gpio, 0);
		mdelay(30);
		dm_gpio_set_value(&aw9523_gpio->reset_gpio, 1);
		mdelay(20);
	}
	
	// set P0 port as push-pull mode
	aw9523_i2c_write(aw9523_gpio, 0x11, 0x10);
	aw9523_i2c_write(aw9523_gpio, 0x12, 0xff);
	aw9523_i2c_write(aw9523_gpio, 0x13, 0xff);
	// P0 and P1 port output mode
	aw9523_i2c_write(aw9523_gpio, 0x04, 0x00);
	aw9523_i2c_write(aw9523_gpio, 0x05, 0x00);
	// disable interrupt function of P0 and P1 port
	aw9523_i2c_write(aw9523_gpio, 0x06, 0xff);
	aw9523_i2c_write(aw9523_gpio, 0x07, 0xff);
	// P0 and P1 port output low level
	aw9523_i2c_write(aw9523_gpio, 0x02, 0x00);
	aw9523_i2c_write(aw9523_gpio, 0x03, 0x00);
	
/*
	ret = gpio_request_by_name(dev, "aw9523_int-gpios", 0,
				   &aw9523_gpio->pwr_up_gpio, GPIOD_IS_OUT);
	if (ret) {
		printf("Cannot get pwr_up_gpio GPIO: %d\n", ret);
		return ret;
	}
*/
	printf("====>aw9523 gpio probe successful!!");
	return 0;
}

static const struct udevice_id aw9523_of_match[] = {
	{ .compatible = "awinic,aw9523_gpio" },
	{}
};

U_BOOT_DRIVER(aw9523_gpio) = {
	.name = "aw9523_gpio",
	.id = UCLASS_I2C_GENERIC,
	.of_match = aw9523_of_match,
	.ops	= &aw9523_gpio_ops,
	.probe = aw9523_probe,
	.bind = dm_scan_fdt_dev,
	.priv_auto_alloc_size = sizeof(struct aw9523_gpio),
};

aw9523由i2c控制,所以这里id为UCLASS_I2C_GENERIC,of_match 中的关键字应与dts中的compatible一致,bind函数固定为dm_scan_fdt_dev,在kconfig和Makefile中添加编译项,在defconfig中添加编译模块需要的宏

如需debug需要在defconfig中修改CONFIG_BOOTDELAY时间,进入uboot 命令模式,打开CONFIG_CMD_I2C=y,不然在ubot命令模式下没有i2c测试命令,关于i2c命令可以参考《uboot中 使用i2c

使用dm tree 可以看到注册上的 uclass,udevice
在这里插入图片描述
这里好像有点问题,第三列显示aw9523@59没有probed,但现在lcm显示了,所以电源肯定是上电完成了,之前只有一个aw9523时显示的probed,由于在rockchip rk3588平台uboot中这部分注册没有log,我也不知道怎么打开,所以暂时没管

i2c 命令测试,相关命令代码在uboot/cmd/i2c.c中
在这里插入图片描述
运行了上面的命令后,aw9523@59显示probed,有点不清楚这是怎么个机制,有知道的同学望告知一下
在这里插入图片描述


没有probe的原因搞清楚了
uboot-dm probe 需要主动去调用下。
参考 https://cloud.tencent.com/developer/article/1571947


	#define aw9523_get_ops(dev)   ((struct dm_aw9523_ops *)(dev)->driver->ops)



	struct udevice *aw9523_dev;
	const struct dm_aw9523_ops *ops = NULL;

	ret = uclass_get_device_by_name(UCLASS_I2C_GENERIC,"aw9523@59", &aw9523_dev);
	if(ret < 0)
		printf(">>>>>get device fail\n");

	if(aw9523_dev)
		ops = aw9523_get_ops(aw9523_dev);
	.......

	if(ops->set_value)
	{
		//enable aw9523 gpio expander port0~2 for LCM power
		ops->set_value(0, 1);
		mdelay(20);
		ops->set_value(1, 1);
		mdelay(20);
		ops->set_value(2, 1);
		mdelay(20);
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

autho

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值