由于之后的触摸屏驱动分析中使用到了GPIO子系统和i2c子系统,因此在分析触摸屏驱动之前我准备把这两个子系统进行简单分析。
之前我们使用GPIO引脚的方式并不是推荐的方式,当我们更改某一bit时,很有可能导致另外的bit值发生更改。而GPIO子系统进行了封装,确保每次只对一个GPIO引脚操作,而不会影响到别的GPIO引脚。
下面这段代码是我从驱动程序中摘出来的,它首先获取GPIO引脚,之后设置为输出模式。
1 ret = gpio_request(EXYNOS4_GPL0(2), "TP1_EN"); 2 if (ret) { 3 printk(KERN_ERR "failed to request TP1_EN for I2C control\n"); 4 //return err; 5 } 6 7 gpio_direction_output(EXYNOS4_GPL0(2), 1); 8 9 s3c_gpio_cfgpin(EXYNOS4_GPL0(2), S3C_GPIO_OUTPUT); 10 gpio_free(EXYNOS4_GPL0(2)); 11 12 mdelay(5);
gpio_direction_output()方便我们操作GPIO引脚,我们来看一下gpio_direction_output()函数会做些什么。
1 int gpio_direction_output(unsigned gpio, int value) 2 { 3 unsigned long flags; 4 struct gpio_chip *chip; /* 不同单板对应不同chip,由芯片厂实现 */ 5 struct gpio_desc *desc = &gpio_desc[gpio]; 6 int status = -EINVAL; 7 8 spin_lock_irqsave(&gpio_lock, flags); 9 /* 判断gpio是否可用 */ 10 if (!gpio_is_valid(gpio)) 11 goto fail; 12 chip = desc->chip; 13 if (!chip || !chip->set || !chip->direction_output) 14 goto fail; 15 gpio -= chip->base; 16 if (gpio >= chip->ngpio) 17 goto fail; 18 status = gpio_ensure_requested(desc, gpio); 19 if (status < 0) 20 goto fail; 21 22 /* now we know the gpio is valid and chip won't vanish */ 23 24 spin_unlock_irqrestore(&gpio_lock, flags); 25 26 might_sleep_if(chip->can_sleep); 27 28 if (status) { 29 status = chip->request(chip, gpio); 30 if (status < 0) { 31 pr_debug("GPIO-%d: chip request fail, %d\n", 32 chip->base + gpio, status); 33 /* and it's not available to anyone else ... 34 * gpio_request() is the fully clean solution. 35 */ 36 goto lose; 37 } 38 } 39 /* 调用chip的direction_output()函数 */ 40 status = chip->direction_output(chip, gpio, value); 41 if (status == 0) 42 set_bit(FLAG_IS_OUT, &desc->flags); 43 trace_gpio_value(chip->base + gpio, 0, value); 44 trace_gpio_direction(chip->base + gpio, 0, status); 45 lose: 46 return status; 47 fail: 48 spin_unlock_irqrestore(&gpio_lock, flags); 49 if (status) 50 pr_debug("%s: gpio-%d status %d\n", 51 __func__, gpio, status); 52 return status; 53 } 54 EXPORT_SYMBOL_GPL(gpio_direction_output);
通过代码第4行struct gpio_chip,我们可以推断出此结构体是内核提供给各个板商的,用于其实现不同GPIO引脚操作。
在drivers/gpio/目录下,有跟平台相关的文件,这些文件就是由厂商提供的GPIO引脚操作函数。在此我以gpio-omap.c为例进行讨论
我们先来查看probe()函数:
1 static int __devinit omap_gpio_probe(struct platform_device *pdev) 2 { 3 static int gpio_init_done; 4 struct omap_gpio_platform_data *pdata; 5 struct resource *res; 6 int id; 7 struct gpio_bank *bank; 8 ... 9 pdata = pdev->dev.platform_data; 10 ... 11 ret = init_gpio_info(pdev); 12 ... 13 id = pdev->id; 14 bank = &gpio_bank[id]; 15 16 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 17 ... 18 bank->irq = res->start; 19 bank->virtual_irq_start = pdata->virtual_irq_start; 20 bank->method = pdata->bank_type; 21 bank->dev = &pdev->dev; 22 bank->dbck_flag = pdata->dbck_flag; 23 bank->stride = pdata->bank_stride; 24 bank_width = pdata->bank_width; 25 26 spin_lock_init(&bank->lock); 27 28 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 29 30 bank->base = ioremap(res->start, resource_size(res)); 31 ... 32 omap_gpio_mod_init(bank, id); 33 omap_gpio_chip_init(bank); 34 omap_gpio_show_rev(bank); 35 36 if (!gpio_init_done) 37 gpio_init_done = 1; 38 39 return 0; 40 }