嵌入式开发记录-day44 pinctrl子系统实现led驱动
1、pinctrl子系统提供给驱动的API接口
Linux官方参考文档:doc "Documentation/driver-api/pinctl.rst"
例程:page1225
#include <linux/pinctrl/consumer.h>
struct foo_state {
struct pinctrl *p;
struct pinctrl_state *s;
...
};
foo_probe()
{
/* Allocate a state holder named "foo" etc */
struct foo_state *foo = ...;
foo->p = devm_pinctrl_get(&device);
if (IS_ERR(foo->p)) {
/* FIXME: clean up "foo" here */
return PTR_ERR(foo->p);
}
foo->s = pinctrl_lookup_state(foo->p, PINCTRL_STATE_DEFAULT);
if (IS_ERR(foo->s)) {
/* FIXME: clean up "foo" here */
return PTR_ERR(s);
}
ret = pinctrl_select_state(foo->s);
if (ret < 0) {
/* FIXME: clean up "foo" here */
return ret;
}
}
API介绍:page1261.
The semantics of the pinctrl APIs are: - pinctrl_get() is called in process context to obtain a handle to all pinctrl information for a given client device. It will allocate a struct from the kernel memory to hold the pinmux state. All mapping table parsing or similar slow operations take place within this API. - devm_pinctrl_get() is a variant of pinctrl_get() that causes pinctrl_put() to be called automatically on the retrieved pointer when the associated device is removed. It is recommended to use this function over plain pinctrl_get(). - pinctrl_lookup_state() is called in process context to obtain a handle to a specific state for a client device. This operation may be slow, too. - pinctrl_select_state() programs pin controller hardware according to the definition of the state as given by the mapping table. In theory, this is a fast-path operation, since it only involved blasting some register settings into hardware. However, note that some pin controllers may have their registers on a slow/IRQ-based bus, so client devices should not assume they can call pinctrl_select_state() from non-blocking contexts. - pinctrl_put() frees all information associated with a pinctrl handle. - devm_pinctrl_put() is a variant of pinctrl_put() that may be used to explicitly destroy a pinctrl object returned by devm_pinctrl_get(). However, use of this function will be rare, due to the automatic cleanup that will occur even without calling it. pinctrl_get() must be paired with a plain pinctrl_put(). pinctrl_get() may not be paired with devm_pinctrl_put(). devm_pinctrl_get() can optionally be paired with devm_pinctrl_put(). devm_pinctrl_get() may not be paired with plain pinctrl_put(). Usually the pin control core handled the get/put pair and call out to the device drivers bookkeeping operations, like checking available functions and the associated pins, whereas select_state pass on to the pin controller driver which takes care of activating and/or deactivating the mux setting by quickly poking some registers. The pins are allocated for your device when you issue the devm_pinctrl_get() call, after this you should be able to see this in the debugfs listing of all pins.
2、使用pinctrl完成初始化的步骤
A:pinctrl设备树文件中,添加描述,注意在对应的节点下,可以搜索gpl2,在同一级下添加
arch/arm/boot/dts/exynos4412-pinctrl.dtsi // 描述使用了哪一个pin脚 leds_gpios1{ leds_gpios1_on:leds_gpios1-on { samsung,pins = "gpl2-0" ; samsung,pin-function = <1>; samsung,pin-val = <1>; samsung,pin-pud = <EXYNOS_PIN_PULL_UP>; }; leds_gpios1_off:leds_gpios1-off { samsung,pins = "gpl2-0" ; samsung,pin-function = <1>; samsung,pin-val = <0>; samsung,pin-pud = <EXYNOS_PIN_PULL_UP>; }; };
B:设备树中添加引用
vim arch/arm/boot/dts/exynos4412-itop-elite.dts &leds_test_node { status = "okay"; pinctrl-names = "itop-leds1-on","itop-leds1-off"; pinctrl-0 = <&leds_gpios1_on>; pinctrl-1 = <&leds_gpios1_off>; };
C:驱动中使用:
三步:获取一个pinctrl句柄,获取其中一个状态,选取其中一个状态设置
3、API常用的简介
功能:获取pinctrl句柄。---“devm机制”。自己不用管内存相关的操作; struct pinctrl *devm_pinctrl_get(struct device *dev) @dev: the device to obtain the handle for 参数:dev。 返回值:错误码或者pinctrl的句柄。 销毁句柄的函数:devm_pinctrl_put(struct pinctrl *p)。 功能:获取引脚状态。 struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name) 参数p:pinctrl的句柄。 参数name:配置的名字,用于pinctrl检索。 返回:状态或者返回错误码。 功能:设置状态。 int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) 参数p:句柄。 参数state:引脚状态。 返回值:错误,返回错误码。
例程也可以参考:Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt page341的Example 4
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
pinctrl-names的值设置为“default”,就可以调用这个函数,直接初始化。
include/linux/pinctrl/pinctrl-state.h:30:#define PINCTRL_STATE_DEFAULT "default"
4、驱动代码
#include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <dt-bindings/pinctrl/samsung.h> #include <linux/pinctrl/consumer.h> #define DRIVER_NAME "leds_test" //page1225 doc " Documentation/driver-api/pinctl.rst " static int ledpinctrl_probe(struct platform_device * pdev) { struct pinctrl *leds_pin_ctrl; struct pinctrl_state *leds_state; int ret; printk("ledpinctrl init\n"); //1、 获取一个pinctrl句柄 leds_pin_ctrl = devm_pinctrl_get(&pdev->dev); if (IS_ERR(leds_pin_ctrl)) { // 使用宏判断错误信息 printk("leds_pin_ctrl,failed,%d\n",PTR_ERR(leds_pin_ctrl)); return -1; } // 2、获取其中一个状态 leds_state = pinctrl_lookup_state(leds_pin_ctrl,"itop-leds1-on"); if (IS_ERR(leds_state)) { printk("leds_state,failed,%d\n",PTR_ERR(leds_state)); return -1; } // 3、选取其中一个状态设置 ret = pinctrl_select_state(leds_pin_ctrl, leds_state); if(ret<0){ printk("pinctrl_select_state,failed\n"); return -1; } // 释放句柄 devm_pinctrl_put(leds_pin_ctrl); printk("init ok\n"); return 0; } static int ledpinctrl_remove(struct platform_device * pdev) { printk(KERN_ALERT "Goodbye, curel world, this is remove\n"); return 0; } static const struct of_device_id of_ledpinctrl_dt_match[] = { {.compatible = DRIVER_NAME}, {}, }; MODULE_DEVICE_TABLE(of,of_ledpinctrl_dt_match); static struct platform_driver ledpinctrl_driver = { .probe = ledpinctrl_probe, .remove = ledpinctrl_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .of_match_table = of_ledpinctrl_dt_match, }, }; static int ledpinctrl_init(void) { printk(KERN_ALERT "Hello, world\n"); return platform_driver_register(&ledpinctrl_driver); return 0; } static void ledpinctrl_exit(void) { printk(KERN_ALERT "Goodbye, curel world\n"); platform_driver_unregister(&ledpinctrl_driver); } module_init(ledpinctrl_init); module_exit(ledpinctrl_exit); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("rty"); MODULE_DESCRIPTION("topeet4412_regiter_dev_drv");
5、测试
1、修改好设备树,并编译,烧写进内核;
fastboot.exe flash dtb exynos4412-itop-elite.dtb
2、将驱动编译,并加载,查看前后变化
[root@iTOP-4412]# insmod itop4412_of_pinctrl.ko
[ 65.022771] itop4412_of_pinctrl: loading out-of-tree module taints kernel.
[ 65.029143] Hello, world
[ 65.031465] ledpinctrl init
[ 65.033663] init ok
此时led灯亮,测试正常
注意:描述添加那块,需要添加到对应节点下面,会找不到对的描述管脚;

浙公网安备 33010602011771号