我是靠谱客的博主 谨慎小白菜,这篇文章主要介绍基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九)作者信息平台简介摘要移植测试,现在分享给大家,希望可以做个参考。

作者信息

作者: 彭东林

邮箱:pengdonglin137@163.com

QQ:405728433

平台简介

开发板:tiny4412ADK + S700 + 4GB Flash

要移植的内核版本:Linux-4.4.0 (支持device tree)

u-boot版本:友善之臂自带的 U-Boot 2010.12 (为支持uImage启动,做了少许改动)

busybox版本:busybox 1.25

交叉编译工具链: arm-none-linux-gnueabi-gcc

      (gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29))

摘要

    MMA7660是一个三轴加速度传感器,跟exynos4412之间使用I2C接口进行通信,同时MMA7660可以向exynos4412发起外部中断。

    移植MMA7660驱动会涉及到device tree、I2C驱动、中断、输入子系统等几个部分,tiny4412自带的MMA7660驱动程序是不支持设备树的,同时I2C驱动也没有采用设备树,所以主要的工作量就是将MMA7660和I2C驱动程序从非设备树形式转变为设备树的形式。同时借此机会,学习一下有设备树的情况下的设备驱动(MMA7660和I2C)和中断。

移植

一、原理图

下面是MMA7660的在底板原理图:

image

     可以看到,使用的是第3个I2C控制器。

下面是核心板:

  I2C:

image

   XEINT25:

image

二、tiny4412自带的驱动

    tiny4412自带的mma7660驱动并不是采用设备树,但是可以作为我们的参考,在arch/arm/mach-exynos/mach-tiny4412.c中包含了mma7660的板级信息。

MMA7660的板级信息:

复制代码
1
1: #include <linux/mma7660.h>
复制代码
1
2: static struct mma7660_platform_data mma7660_pdata = {
复制代码
1
3: .irq = IRQ_EINT(25),
复制代码
1
4: .poll_interval = 100,
复制代码
1
5: .input_fuzz = 4,
复制代码
1
6: .input_flat = 4,
复制代码
1
7: };
复制代码
1
8: 
复制代码
1
9: static struct s3c2410_platform_i2c tiny4412_i2c3_data __initdata = {
复制代码
1
10: .flags = 0,
复制代码
1
11: .bus_num = 3,
复制代码
1
12: .slave_addr = 0x10,
复制代码
1
13: .frequency = 200*1000,
复制代码
1
14: .sda_delay = 100,
复制代码
1
15: };
复制代码
1
16: 
复制代码
1
17: static struct i2c_board_info i2c_devs3[] __initdata = {
复制代码
1
18: {
复制代码
1
19: I2C_BOARD_INFO("mma7660", 0x4c),
复制代码
1
20: .platform_data = &mma7660_pdata,
复制代码
1
21: },
复制代码
1
22: };
复制代码
1
23: 
复制代码
1
24: static void __init smdk4x12_machine_init(void)
复制代码
1
25: {
复制代码
1
26: ... ...
复制代码
1
27: s3c_i2c3_set_platdata(&tiny4412_i2c3_data);
复制代码
1
28: i2c_register_board_info(3, i2c_devs3, ARRAY_SIZE(i2c_devs3));   // 注册板级信息
复制代码
1
29: ... ...
复制代码
1
30: }

其中,

从上面的信息我们可以知道:

MMA7660的器件地址是0x4c,I2C3的CLK信号新的频率为200KHz。这两个信息比较重要。MMA7660的驱动程序是linux-3.0.86/drivers/hwmon/mma7660.c。

I2C的板级信息:

在arch/arm/plat-samsung/dev-i2c3.c中:

复制代码
1
1: /* linux/arch/arm/plat-samsung/dev-i2c3.c
复制代码
1
2: *
复制代码
1
3: * Copyright (c) 2010 Samsung Electronics Co., Ltd.
复制代码
1
4: * http://www.samsung.com/
复制代码
1
5: *
复制代码
1
6: * S5P series device definition for i2c device 3
复制代码
1
7: *
复制代码
1
8: * This program is free software; you can redistribute it and/or modify
复制代码
1
9: * it under the terms of the GNU General Public License version 2 as
复制代码
1
10: * published by the Free Software Foundation.
复制代码
1
11: */
复制代码
1
12: 
复制代码
1
13: #include <linux/gfp.h>
复制代码
1
14: #include <linux/kernel.h>
复制代码
1
15: #include <linux/string.h>
复制代码
1
16: #include <linux/platform_device.h>
复制代码
1
17: 
复制代码
1
18: #include <mach/irqs.h>
复制代码
1
19: #include <mach/map.h>
复制代码
1
20: 
复制代码
1
21: #include <plat/regs-iic.h>
复制代码
1
22: #include <plat/iic.h>
复制代码
1
23: #include <plat/devs.h>
复制代码
1
24: #include <plat/cpu.h>
复制代码
1
25: 
复制代码
1
26: static struct resource s3c_i2c_resource[] = {
复制代码
1
27: [0] = {
复制代码
1
28: .start = S3C_PA_IIC3,
复制代码
1
29: .end = S3C_PA_IIC3 + SZ_4K - 1,
复制代码
1
30: .flags = IORESOURCE_MEM,
复制代码
1
31: },
复制代码
1
32: [1] = {
复制代码
1
33: .start = IRQ_IIC3,
复制代码
1
34: .end = IRQ_IIC3,
复制代码
1
35: .flags = IORESOURCE_IRQ,
复制代码
1
36: },
复制代码
1
37: };
复制代码
1
38: 
复制代码
1
39: struct platform_device s3c_device_i2c3 = {
复制代码
1
40: .name = "s3c2440-i2c",
复制代码
1
41: .id = 3,
复制代码
1
42: .num_resources = ARRAY_SIZE(s3c_i2c_resource),
复制代码
1
43: .resource = s3c_i2c_resource,
复制代码
1
44: };
复制代码
1
45: 
复制代码
1
46: void __init s3c_i2c3_set_platdata(struct s3c2410_platform_i2c *pd)
复制代码
1
47: {
复制代码
1
48: struct s3c2410_platform_i2c *npd;
复制代码
1
49: 
复制代码
1
50: if (!pd) {
复制代码
1
51: pd = &default_i2c_data;
复制代码
1
52: pd->bus_num = 3;
复制代码
1
53: }
复制代码
1
54: 
复制代码
1
55: npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c),
复制代码
1
56: &s3c_device_i2c3);
复制代码
1
57: 
复制代码
1
58: if (!npd->cfg_gpio)
复制代码
1
59: npd->cfg_gpio = s3c_i2c3_cfg_gpio;
复制代码
1
60: }

然后会在arch/arm/mach-exynos/mach-tiny4412.c中注册:

复制代码
1
1: static struct platform_device *smdk4x12_devices[] __initdata = {
复制代码
1
2: ... ...
复制代码
1
3: &s3c_device_i2c3,
复制代码
1
4: ... ...
复制代码
1
5: }
复制代码
1
6: 
复制代码
1
7: static void __init smdk4x12_machine_init(void)
复制代码
1
8: {
复制代码
1
9: ... ...
复制代码
1
10: platform_add_devices(smdk4x12_devices, ARRAY_SIZE(smdk4x12_devices));
复制代码
1
11: ... ...
复制代码
1
12: }

I2C控制器对应的驱动是linux-3.0.86/drivers/i2c/busses/i2c-s3c2410.c。

三、移植

1、首先把MMA7660和I2C控制器的板级信息转化为设备树的形式,修改arch/arm/boot/dts/exynos4412-tiny4412.dts,添加MMA7660和I2C的硬件信息,可以参考内核文档:Documentation/devicetree/bindings/i2c/i2c.txt和Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt,中断资源的填写可以参考内核文档Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt。

复制代码
1
1: /* MMA7660FC */
复制代码
1
2: &i2c_3 {
复制代码
1
3: samsung,i2c-sda-delay = <100>;
复制代码
1
4: samsung,i2c-slave-addr = <0x10>;
复制代码
1
5: samsung,i2c-max-bus-freq = <200000>;
复制代码
1
6: pinctrl-0 = <&i2c3_bus>;
复制代码
1
7: pinctrl-names = "default";
复制代码
1
8: status = "okay";
复制代码
1
9: 
复制代码
1
10: mma7660@4c {
复制代码
1
11: compatible = "freescale,mma7660";
复制代码
1
12: reg = <0x4c>;
复制代码
1
13: interrupt-parent = <&gpx3>;
复制代码
1
14: interrupts = <1 2>;
复制代码
1
15: poll_interval = <100>;
复制代码
1
16: input_fuzz = <4>;
复制代码
1
17: input_flat = <4>;
复制代码
1
18: status = "okay";
复制代码
1
19: };
复制代码
1
20: };

上面的信息基本上是把原来的板级信息搬过来。

第13行和第14行是设置中断资源,参考Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt:

复制代码
1
External GPIO and Wakeup Interrupts:
复制代码
1
 
复制代码
1
The controller supports two types of external interrupts over gpio. The first
复制代码
1
is the external gpio interrupt and second is the external wakeup interrupts.
复制代码
1
The difference between the two is that the external wakeup interrupts can be
复制代码
1
used as system wakeup events.
复制代码
1
 
复制代码
1
A. External GPIO Interrupts: For supporting external gpio interrupts, the
复制代码
1
following properties should be specified in the pin-controller device node.
复制代码
1
 
复制代码
1
- interrupt-parent: phandle of the interrupt parent to which the external
复制代码
1
GPIO interrupts are forwarded to.
复制代码
1
- interrupts: interrupt specifier for the controller. The format and value of
复制代码
1
the interrupt specifier depends on the interrupt parent for the controller.
复制代码
1
 
复制代码
1
In addition, following properties must be present in node of every bank
复制代码
1
of pins supporting GPIO interrupts:
复制代码
1
 
复制代码
1
- interrupt-controller: identifies the controller node as interrupt-parent.
复制代码
1
- #interrupt-cells: the value of this property should be 2.
复制代码
1
- First Cell: represents the external gpio interrupt number local to the
复制代码
1
external gpio interrupt space of the controller.
复制代码
1
- Second Cell: flags to identify the type of the interrupt
复制代码
1
- 1 = rising edge triggered
复制代码
1
- 2 = falling edge triggered
复制代码
1
- 3 = rising and falling edge triggered
复制代码
1
- 4 = high level triggered
复制代码
1
- 8 = low level triggered

对于interrupts = <1 2>,其中1表示GPX3_1,2表示的是下降沿触发。

第2行的i2c_3是一个标号,i2c3的其他信息是在arch/arm/boot/dts/exynos4.dtsi中:

复制代码
1
1: i2c_3: i2c@13890000 {
复制代码
1
2: #address-cells = <1>;
复制代码
1
3: #size-cells = <0>;
复制代码
1
4: compatible = "samsung,s3c2440-i2c";
复制代码
1
5: reg = <0x13890000 0x100>;
复制代码
1
6: interrupts = <0 61 0>;
复制代码
1
7: clocks = <&clock CLK_I2C3>;
复制代码
1
8: clock-names = "i2c";
复制代码
1
9: pinctrl-names = "default";
复制代码
1
10: pinctrl-0 = <&i2c3_bus>;
复制代码
1
11: status = "disabled";
复制代码
1
12: };

第10行是设置GPIO的功能复用,i2c3_bus是在文件arch/arm/boot/dts/exynos4x12-pinctrl.dtsi中:

复制代码
1
1: i2c3_bus: i2c3-bus {
复制代码
1
2: samsung,pins = "gpa1-2", "gpa1-3";
复制代码
1
3: samsung,pin-function = <3>;
复制代码
1
4: samsung,pin-pud = <3>;
复制代码
1
5: samsung,pin-drv = <0>;
复制代码
1
6: };

那么是在什么时候解析这部分,然后设置功能复用的呢?这个以后再说。

2、填写完板级信息,接下来就要移植驱动程序了,其中I2C控制器的驱动程序Linux内核已经写好了,就是drivers/i2c/busses/i2c-s3c2410.c。MMA7660的驱动程序就需要我们自己移植了。

  • 注册
复制代码
1
1: static const struct i2c_device_id mma7660_ids[] = {
复制代码
1
2: { "mma7660", 0 },
复制代码
1
3: { },
复制代码
1
4: };
复制代码
1
5: MODULE_DEVICE_TABLE(i2c, mma7660_ids);
复制代码
1
6: 
复制代码
1
7: #ifdef CONFIG_OF
复制代码
1
8: static const struct of_device_id mma7660_dt_match[] = {
复制代码
1
9: { .compatible = "freescale,mma7660" },
复制代码
1
10: { }
复制代码
1
11: };
复制代码
1
12: MODULE_DEVICE_TABLE(of, mma7660_dt_match);
复制代码
1
13: #endif
复制代码
1
14: 
复制代码
1
15: static struct i2c_driver mma7660_driver = {
复制代码
1
16: .driver = {
复制代码
1
17: .name = MMA7660_NAME,
复制代码
1
18: .pm = &mma7660_pm_ops,
复制代码
1
19: .of_match_table = of_match_ptr(mma7660_dt_match),
复制代码
1
20: },
复制代码
1
21: .probe = mma7660_probe,
复制代码
1
22: .remove = mma7660_remove,
复制代码
1
23: .id_table = mma7660_ids,
复制代码
1
24: };
复制代码
1
25: 
复制代码
1
26: module_i2c_driver(mma7660_driver);
  • 解析设备树
复制代码
1
1: static struct mma7660_platform_data *mma7660_parse_dt(struct device *dev)
复制代码
1
2: {
复制代码
1
3: struct mma7660_platform_data *pdata;
复制代码
1
4: struct device_node *np = dev->of_node;
复制代码
1
5: 
复制代码
1
6: if (!np)
复制代码
1
7: return NULL;
复制代码
1
8: 
复制代码
1
9: pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
复制代码
1
10: if (!pdata) {
复制代码
1
11: dev_err(dev, "failed to allocate platform datan");
复制代码
1
12: return NULL;
复制代码
1
13: }
复制代码
1
14: 
复制代码
1
15: if (of_property_read_u32(np, "poll_interval", &pdata->poll_interval)) {
复制代码
1
16: dev_err(dev, "failed to get poll_interval propertyn");
复制代码
1
17: return NULL;
复制代码
1
18: }
复制代码
1
19: 
复制代码
1
20: if (of_property_read_u32(np, "input_fuzz", &pdata->input_fuzz)) {
复制代码
1
21: dev_err(dev, "failed to get input_fuzz propertyn");
复制代码
1
22: return NULL;
复制代码
1
23: }
复制代码
1
24: 
复制代码
1
25: if (of_property_read_u32(np, "input_flat", &pdata->input_flat)) {
复制代码
1
26: dev_err(dev, "failed to get input_flat propertyn");
复制代码
1
27: return NULL;
复制代码
1
28: }
复制代码
1
29: 
复制代码
1
30: return pdata;
复制代码
1
31: }

关于这部分我已经把代码上传到github上了,下载方法:

复制代码
1
git clone https://github.com/pengdonglin137/linux-4.4_tiny4412.git -b port_to_tiny4412

测试

复制代码
1
1: [root@tiny4412 root]# cd /sys/bus/i2c/devices/3-004c/
复制代码
1
2: [root@tiny4412 3-004c]# ls
复制代码
1
3: all_axis_g input of_node subsystem x_axis_g
复制代码
1
4: driver modalias power tilt_status y_axis_g
复制代码
1
5: hwmon name registers uevent z_axis_g
复制代码
1
6: [root@tiny4412 3-004c]# cat all_axis_g
复制代码
1
7: 2, 0, 22
复制代码
1
8: [root@tiny4412 3-004c]# cat registers
复制代码
1
9: REG: 0x00 = 0x03 ...... [ 0000 0011 ]
复制代码
1
10: REG: 0x01 = 0x01 ...... [ 0000 0001 ]
复制代码
1
11: REG: 0x02 = 0x16 ...... [ 0001 0110 ]
复制代码
1
12: REG: 0x03 = 0x01 ...... [ 0000 0001 ]
复制代码
1
13: REG: 0x04 = 0x02 ...... [ 0000 0010 ]
复制代码
1
14: REG: 0x05 = 0xa0 ...... [ 1010 0000 ]
复制代码
1
15: REG: 0x06 = 0xe7 ...... [ 1110 0111 ]
复制代码
1
16: REG: 0x07 = 0x59 ...... [ 0101 1001 ]
复制代码
1
17: REG: 0x08 = 0x49 ...... [ 0100 1001 ]
复制代码
1
18: REG: 0x09 = 0x04 ...... [ 0000 0100 ]
复制代码
1
19: REG: 0x0a = 0x0f ...... [ 0000 1111 ]

用hexdump看看上报的事件:

复制代码
1
1: [root@tiny4412 ]# hexdump /dev/input/event0
复制代码
1
2: 0000000 0013 0000 9b6a 0001 0003 0002 0015 0000
复制代码
1
3: 0000010 0013 0000 9b6a 0001 0000 0000 0000 0000
复制代码
1
4: 0000020 0013 0000 4015 0009 0003 0000 0002 0000
复制代码
1
5: 0000030 0013 0000 4015 0009 0000 0000 0000 0000
复制代码
1
6: 0000040 0018 0000 c6b5 000a 0003 0000 0004 0000
复制代码
1
7: 0000050 0018 0000 c6b5 000a 0000 0000 0000 0000
复制代码
1
8: 0000060 0019 0000 9ef7 0001 0003 0000 0006 0000
复制代码
1
9: 0000070 0019 0000 9ef7 0001 0000 0000 0000 0000
复制代码
1
10: 0000080 0019 0000 c6b3 000a 0003 0000 0005 0000
复制代码
1
11: 0000090 0019 0000 c6b3 000a 0000 0000 0000 0000
复制代码
1
12: 00000a0 0019 0000 d3f0 000d 0003 0000 0004 0000
复制代码
1
13: 00000b0 0019 0000 d3f0 000d 0000 0000 0000 0000
复制代码
1
14: 00000c0 001a 0000 25c1 0003 0003 0000 0003 0000
复制代码
1
15: 00000d0 001a 0000 25c1 0003 0000 0000 0000 0000
复制代码
1
16: 00000e0 001a 0000 32d0 0006 0003 0000 0002 0000
复制代码
1
17: 00000f0 001a 0000 32d0 0006 0000 0000 0000 0000
复制代码
1
18: 0000100 001a 0000 b980 0007 0003 0000 0001 0000
复制代码
1
19: 0000110 001a 0000 b980 0007 0000 0000 0000 0000

未完待续…

最后

以上就是谨慎小白菜最近收集整理的关于基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九)作者信息平台简介摘要移植测试的全部内容,更多相关基于tiny4412的Linux内核移植内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(94)

评论列表共有 0 条评论

立即
投稿
返回
顶部