觉得为时已晚的时候,恰恰是最早的时候
用 ADB 操作 GPIO
转载请注明出处 https://sayid95.github.io/
背景介绍:mt8167 安卓7.0
我们经常会在底层驱动里面去操作gpio,进而去控制硬件。如果驱动层面去操作io出现问题的时候,我们不知道是不是硬件的问题,今天就来说下怎么用ADB去控制gpio。
首先
打开很难用的 Windows 的cmd.exe (推荐 一款替代品 Cmder ),adb shell连接上设备以后,输入下面的命令,
cd /sys/devices/platform/soc/1000b000.pinctrl/
进入到1000b000.pinctrl/ 的目录下,然后就可以去操作 io 口了,如下:
echo mode 66 0 > mt_gpio /*设置66号 io 的模式*/
echo dir 66 1 > mt_gpio /*设置66号 io 的输入,输出方向*/
echo out 66 1 > mt_gpio /*设置66号 io 为输出*/
接着
就可以用下面的命令去看我们上面用 ADB 设置的 gpio 状态了
cat /sys/devices/platform/soc/1000b000.pinctrl/mt_gpio
来看下mtk 这部分操作的源码
在 kernel-4.4/drivers/pinctrl/mediatek/pinctrl-mtk-common.c 这个文件里,下面代码就是adb 直接操作gpio的函数:
static ssize_t mt_gpio_show_pin(struct device *dev, struct device_attribute *attr, char *buf)
{
int len = 0;
int bufLen = PAGE_SIZE;
struct mtk_pinctrl *pctl = dev_get_drvdata(dev);
struct gpio_chip *chip = pctl->chip;
unsigned i;
int pull_val;
len += snprintf(buf+len, bufLen-len,
"PIN: [MODE] [DIR] [DOUT] [DIN] [PULL_EN] [PULL_SEL] [IES] [SMT] [DRIVE] ( [R1] [R0] )\n");
for (i = 0; i < chip->ngpio; i++) {
pull_val = mtk_pullsel_get(chip, i);
len += snprintf(buf+len, bufLen-len, "%4d:% d% d% d% d% d% d% d% d% d",
i,
mtk_pinmux_get(chip, i),
mtk_gpio_get_direction(chip, i),
mtk_gpio_get_out(chip, i),
mtk_gpio_get_in(chip, i),
mtk_pullen_get(chip, i),
(pull_val >= 0) ? (pull_val&1) : -1,
mtk_ies_get(chip, i),
mtk_smt_get(chip, i),
mtk_driving_get(chip, i));
if ((pull_val & 8) && (pull_val >= 0))
len += snprintf(buf+len, bufLen-len, " %d %d", !!(pull_val&4), !!(pull_val&2));
len += snprintf(buf+len, bufLen-len, "\n");
}
return len;
}
static ssize_t mt_gpio_store_pin(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int pin, val;
int val_set;
struct mtk_pinctrl *pctl = dev_get_drvdata(dev);
struct pinctrl_dev *pctldev = pctl->pctl_dev;
if (!strncmp(buf, "mode", 4) && (sscanf(buf+4, "%d %d", &pin, &val) == 2)) {
val_set = mtk_pmx_set_mode(pctldev, pin, val);
} else if (!strncmp(buf, "dir", 3) && (sscanf(buf+3, "%d %d", &pin, &val) == 2)) {
val_set = mtk_pmx_gpio_set_direction(pctldev, NULL, pin, !val);
} else if (!strncmp(buf, "out", 3) && (sscanf(buf+3, "%d %d", &pin, &val) == 2)) {
mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false);
mtk_gpio_set(pctl->chip, pin, val);
} else if (!strncmp(buf, "pullen", 6) && (sscanf(buf+6, "%d %d", &pin, &val) == 2)) {
val_set = mtk_pconf_set_pull_select(pctl, pin, !!val,
false, MTK_PUPD_SET_R1R0_00 + val);
} else if (!strncmp(buf, "pullsel", 7) && (sscanf(buf+7, "%d %d", &pin, &val) == 2)) {
val_set = mtk_pconf_set_pull_select(pctl, pin, true, !!val, MTK_PUPD_SET_R1R0_01);
} else if (!strncmp(buf, "ies", 3) && (sscanf(buf+3, "%d %d", &pin, &val) == 2)) {
val_set = mtk_pconf_set_ies_smt(pctl, pin, val, PIN_CONFIG_INPUT_ENABLE);
} else if (!strncmp(buf, "smt", 3) && (sscanf(buf+3, "%d %d", &pin, &val) == 2)) {
val_set = mtk_pconf_set_ies_smt(pctl, pin, val, PIN_CONFIG_INPUT_SCHMITT_ENABLE);
}
return count;
}
static DEVICE_ATTR(mt_gpio, 0664, mt_gpio_show_pin, mt_gpio_store_pin);
static struct device_attribute *gpio_attr_list[] = {
&dev_attr_mt_gpio,
};
static int mt_gpio_create_attr(struct device *dev)
{
int idx, err = 0;
int num = (int)(ARRAY_SIZE(gpio_attr_list));
if (!dev)
return -EINVAL;
for (idx = 0; idx < num; idx++) {
err = device_create_file(dev, gpio_attr_list[idx]);
if (err)
break;
}
return err;
}
看到源码 static DEVICE_ATTR(mt_gpio, 0664, mt_gpio_show_pin, mt_gpio_store_pin);,我们就知道其实就是利用 device_create_file 函数可以在 /sys/ 下创建对应的属性文件,从而通过对该文件的读写实现特定的数据操作。
可能不同的内核对应的节点不一样,这个例子是在 Linux 4.4下进行的,现在就去试试吧!
网友评论