RK平台添加GPIO通用接口(设置GPIO属性)

背景: PCB版过硬件认证时需一些PIN的复用功能控制,因通用GPIO库未提供相关接口,需自己添加接口供外部驱动调用。


平台:PX30

OS:android8.1


1.先通过dts中的pin-control 配置原理找到设置复用功能的接口函数。
配置的dts写法

		uart0 {
			uart0_xfer: uart0-xfer {
				rockchip,pins =
					<0 RK_PB2 RK_FUNC_1 &pcfg_pull_up>,
					<0 RK_PB3 RK_FUNC_1 &pcfg_pull_up>;
			};

			uart0_cts: uart0-cts {
				rockchip,pins =
					<0 RK_PB4 RK_FUNC_1 &pcfg_pull_none>;
			};

			uart0_rts: uart0-rts {
				rockchip,pins =
					<0 RK_PB5 RK_FUNC_1 &pcfg_pull_none>;
			};

			uart0_rts_gpio: uart0-rts-gpio {
				rockchip,pins =
					<0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
			};
		};

根据原理图可知GPIO0-B2,GPIO0-B3,只有GPIO和uart两种功能复用,并且在dts 默认配置成串口,根据dts 解析找到驱动在kernel/drivers/pinctrl/pinctrl-rockchip.c中进行设置,找到函数rockchip_set_mux:

static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
{
	struct rockchip_pinctrl *info = bank->drvdata;
	int iomux_num = (pin / 8);
	struct regmap *regmap;
	int reg, ret, mask, mux_type;
	u8 bit;
	u32 data, rmask, route_reg, route_val;

	ret = rockchip_verify_mux(bank, pin, mux);
	if (ret < 0)
		return ret;

	if (bank->iomux[iomux_num].type & IOMUX_GPIO_ONLY)
		return 0;

	dev_dbg(info->dev, "setting mux of GPIO%d-%d to %d\n",
						bank->bank_num, pin, mux);

	//gpio0 B2
	if ((bank->bank_num == 0) && (pin == 10)) 
	{
		printk("setting mux of GPIO%d-%d to %d\n",
		bank->bank_num, pin, mux);
		dump_stack();
	}	

	regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
				? info->regmap_pmu : info->regmap_base;
	
	/* get basic quadrupel of mux registers and the correct reg inside */
	mux_type = bank->iomux[iomux_num].type;
	reg = bank->iomux[iomux_num].offset;
	if (mux_type & IOMUX_WIDTH_4BIT) {
		if ((pin % 8) >= 4)
			reg += 0x4;
		bit = (pin % 4) * 4;
		mask = 0xf;
	} else if (mux_type & IOMUX_WIDTH_3BIT) {
		if ((pin % 8) >= 5)
			reg += 0x4;
		bit = (pin % 8 % 5) * 3;
		mask = 0x7;
	} else {
		bit = (pin % 8) * 2;
		mask = 0x3;
	}

	if (bank->recalced_mask & BIT(pin))
		rockchip_get_recalced_mux(bank, pin, &reg, &bit, &mask);

	if (bank->route_mask & BIT(pin)) {
		if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
					   &route_val)) {
			ret = regmap_write(regmap, route_reg, route_val);
			if (ret)
				return ret;
		}
	}

	if (mux_type & IOMUX_WRITABLE_32BIT) {
		ret = regmap_read(regmap, reg, &data);
		if (ret)
			return ret;

		data &= ~(mask << bit);
		data |= (mux & mask) << bit;
		ret = regmap_write(regmap, reg, data);
	} else {
		data = (mask << (bit + 16));
		rmask = data | (data >> 16);
		data |= (mux & mask) << bit;
		ret = regmap_update_bits(regmap, reg, rmask, data);
	}

	return ret;
}

查看函数结构,最后也是通过写寄存器的方式去更新GPIO的功能状态。但是此接口使用的参数:
struct rockchip_pinctrl,struct rockchip_pin_bank,都是函数内部结构体,不可作为外部接口使用,
通过通用的gpio_direction_output等通用接口的封装过程,发现接口都是通过gpio_chip接口进行封装的。找到回调函数:

static const struct gpio_chip rockchip_gpiolib_chip = {
	.request = gpiochip_generic_request,
	.free = gpiochip_generic_free,
	.set = rockchip_gpio_set,
	.get = rockchip_gpio_get,
	.get_direction	= rockchip_gpio_get_direction,
	.direction_input = rockchip_gpio_direction_input,
	.direction_output = rockchip_gpio_direction_output,
	.to_irq = rockchip_gpio_to_irq,
	.set_mux = rockchip_gpio_set_mux,
	.owner = THIS_MODULE,
};

其中.set_mux = rockchip_gpio_set_mux为自己添加,实现原型

static int rockchip_gpio_set_mux(struct gpio_chip *gc, unsigned offset ,int value)
{
	int ret = 0;
	struct rockchip_pin_bank *bank = gpiochip_get_data(gc);

	ret = rockchip_set_mux(bank, offset, value);
	
	return ret;		
}

函数接口部分已经实现完成了,最后只需要将接口通用化。
2.添加通用接口函数
kernel/include/linux/gpio/driver.h中

struct gpio_chip {
	int			(*request)(struct gpio_chip *chip,
						unsigned offset);
	void		(*free)(struct gpio_chip *chip,
						unsigned offset);
	int			(*get_direction)(struct gpio_chip *chip,
						unsigned offset);
	int			(*direction_input)(struct gpio_chip *chip,
	.......
	int         (*set_mux)(struct gpio_chip *chip,
						unsigned offset, int value);
}

kernel/drivers/gpio/gpiolib.c中添加外部接口调用函数

int gpiod_set_mux(struct gpio_desc *desc, int value)
{
	struct gpio_chip	*chip;
	int			status = -EINVAL;
	if (!desc || !desc->chip) {
		pr_warn("%s: invalid GPIO\n", __func__);
		return -EINVAL;
	}
	
	chip = desc->chip;
	status = chip->set_mux(chip, gpio_chip_hwgpio(desc),value);
	
	return status;
}
EXPORT_SYMBOL_GPL(gpiod_set_mux);

最后封装函数为通用接口,及加上函数声明即可:
kernel/include/asm-generic/gpio.h中进行函数封装

static inline int gpio_set_mux(unsigned gpio,int value)
{	
	return gpiod_set_mux(gpio_to_desc(gpio), value);
}

kernel/include/linux/gpio/consumer.h中添加声明

int gpiod_set_mux(struct gpio_desc *desc, int value);

到这儿,函数接口已经添加完成,可正常使用,提供一个使用实例(此驱动为自己编写的一个字符驱动,此接口可当做GPIO通用接口使用,不局限场景):

//设置pin10,11(GPIO0-B2,B3)模式
void set_mode(int value)
{
	switch(value)
	{
		case MODE_UART:
			gpio_set_mux(MEDICAL_BP_UART_TX,RK_FUNC_1);
			gpio_set_mux(MEDICAL_BP_UART_RX,RK_FUNC_1);

			gpio_free(MEDICAL_BP_UART_RX);
			gpio_free(MEDICAL_BP_UART_TX);
			break;
		case MODE_GPIO:
			gpio_request(MEDICAL_BP_UART_TX,"medical_uart_tx");
			gpio_request(MEDICAL_BP_UART_RX,"medical_uart_tx");
   
			gpio_direction_output(MEDICAL_BP_UART_TX,0);
			gpio_direction_output(MEDICAL_BP_UART_RX,0); //init to GPIO low
			break;
		default:break;	
	}
}

调用时需注意,首先需要将pin request 成GPIO,然后通过GPIO的属性去修改他的mux复用功能,pin func 功能可查看mcu,pin说明去确认复用类型,对应修改参数即可。设置完成属性后,因属性已不在是GPIO FUNC ,则需要释放此GPIO,这样就能达到设置属性的功能。

如有疑问,或编辑有误地方,还请提出,谢谢观看!

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值