4978|4

854

帖子

0

TA的资源

五彩晶圆(中级)

楼主
 

从android 4.0 S5PV210 touch 驱动学习platform device 和platform driver [复制链接]

https://bbs.eeworld.com.cn/thread-374391-1-1.html
这篇文章看,可以学到不少,现在自己来分析一下实际的驱动-从android 4.0 S5PV210 touch 驱动学习platform device 和platform driver
点赞 关注
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460

回复
举报

854

帖子

0

TA的资源

五彩晶圆(中级)

沙发
 
static struct platform_device *smdkv210_devices[] __initdata = {
        &s3c_device_adc,
        &s3c_device_cfcon,
        &s3c_device_fb,
        &s3c_device_hsmmc0,
        &s3c_device_hsmmc1,
        &s3c_device_hsmmc2,
        &s3c_device_hsmmc3,
        &s3c_device_i2c0,
        &s3c_device_i2c1,
        &s3c_device_i2c2,
#ifdef CONFIG_TOUCHSCREEN_EGALAX
        &s3c_device_i2c5,
#endif
        &s3c_device_rtc,
        &s3c_device_ts,
        &s3c_device_wdt,
#ifdef CONFIG_SND_SAMSUNG_AC97
        &s5pv210_device_ac97,
#endif
#ifdef CONFIG_SND_SAMSUNG_I2S
        &s5pv210_device_iis0,
#endif
        &s5pv210_device_spdif,
#ifdef CONFIG_SND_SAMSUNG_PCM
#ifdef CONFIG_SND_SAMSUNG_PCM_USE_I2S1_MCLK
        &s5pv210_device_pcm0,
#endif
#endif         /*end of CONFIG_SND_SAMSUNG_PCM*/
        &samsung_asoc_dma,
        &samsung_device_keypad,
        &smdkv210_dm9000,
        &smdkv210_lcd_lte480wv,
        &s3c_device_timer[3],
        &smdkv210_backlight_device,
        &s5p_device_ehci,
        &s5p_device_ohci,
#ifdef CONFIG_USB_GADGET
        &s3c_device_usbgadget,
#endif
#ifdef CONFIG_VIDEO_FIMC
        &s3c_device_fimc0,
        &s3c_device_fimc1,
        &s3c_device_fimc2,
#endif
#ifdef CONFIG_VIDEO_FIMC_MIPI
        &s3c_device_csis,
#endif
#ifdef CONFIG_VIDEO_JPEG_V2
        &s3c_device_jpeg,
#endif
#ifdef CONFIG_VIDEO_MFC50
        &s3c_device_mfc,
#endif
#ifdef CONFIG_ANDROID_PMEM
        &pmem_gpu1_device,
#endif
#ifdef CONFIG_SPI_S3C64XX
        &s5pv210_device_spi0,
        &s5pv210_device_spi1,
#endif

#ifdef CONFIG_REGULATOR
        &smdkv210_b_pwr_5v,
#endif

#ifdef CONFIG_S5PV210_POWER_DOMAIN
        &s5pv210_pd_tv,
        &s5pv210_pd_lcd,
        &s5pv210_pd_g3d,
        &s5pv210_pd_mfc,
        &s5pv210_pd_audio,
        &s5pv210_pd_cam,  
#endif
        &s3c_device_g3d,
#ifdef CONFIG_VIDEO_G2D
        &s3c_device_g2d,
#endif
#ifdef CONFIG_VIDEO_TV20
        &s5p_device_tvout,
        &s5p_device_cec,
        &s5p_device_hpd,
#endif
};

-------------------------------------------------
static void __init smdkv210_machine_init(void)
{
        s3c_pm_init();

        smdkv210_dm9000_init();
        platform_add_devices(smdkv210_devices, ARRAY_SIZE(smdkv210_devices));

#ifdef CONFIG_ANDROID_PMEM
        android_pmem_set_platdata();
#endif

        samsung_keypad_set_platdata(&smdkv210_keypad_data);
        s3c24xx_ts_set_platdata(&s3c_ts_platform);
......................

.......................
}

void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *pd)
{
        struct s3c2410_ts_mach_info *npd;

        if (!pd) {
                printk(KERN_ERR "%s: no platform data\n", __func__);
                return;
        }

        npd = kmemdup(pd, sizeof(struct s3c2410_ts_mach_info), GFP_KERNEL);
        if (!npd)
                printk(KERN_ERR "%s: no memory for platform data\n", __func__);

        s3c_device_ts.dev.platform_data = npd;
}

static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
        .delay                        = 10000,
        .presc                        = 49,
        .oversampling_shift        = 2,
        .cal_x_max              = 800,
        .cal_y_max              = 480,
        .cal_param              = {
                -13357, -85, 53858048, -95, -8493, 32809514, 65536
        },

};

npd = kmemdup(pd, sizeof(struct s3c2410_ts_mach_info), GFP_KERNEL); 这个是干什么的呢?
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 

回复

854

帖子

0

TA的资源

五彩晶圆(中级)

板凳
 
s3c_device_ts.dev.platform_data = npd;
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 
 

回复

854

帖子

0

TA的资源

五彩晶圆(中级)

4
 

看一下这个The platform device API就明白了

The platform device API
http://lwn.net/Articles/448499/ 原文地址
By Jonathan Corbet
June 21, 2011

In the very early days, Linux users often had to tell the kernel where specific devices were to be found before their systems would work. In the absence of this information, the driver could not know which I/O ports and interrupt line(s) the device was configured to use. Happily, we now live in the days of busses like PCI which have discoverability built into them; any device sitting on a PCI bus can tell the system what sort of device it is and where its resources are. So the kernel can, at boot time, enumerate the devices available and everything Just Works.
Alas, life is not so simple; there are plenty of devices which are still not discoverable by the CPU. In the embedded and system-on-chip world, non-discoverable devices are, if anything, increasing in number. So the kernel still needs to provide ways to be told about the hardware that is actually present. "Platform devices" have long been used in this role in the kernel. This article will describe the interface for platform devices; it is meant as needed background material for a following article on integration with device trees.

Platform drivers
A platform device is represented by struct platform_device, which, like the rest of the relevant declarations, can be found in . These devices are deemed to be connected to a virtual "platform bus"; drivers of platform devices must thus register themselves as such with the platform bus code. This registration is done by way of a platform_driver structure:

    struct platform_driver {        int (*probe)(struct platform_device *);        int (*remove)(struct platform_device *);        void (*shutdown)(struct platform_device *);        int (*suspend)(struct platform_device *, pm_message_t state);        int (*resume)(struct platform_device *);        struct device_driver driver;        const struct platform_device_id *id_table;    };
At a minimum, the probe() and remove() callbacks must be supplied; the other callbacks have to do with power management and should be provided if they are relevant.
The other thing the driver must provide is a way for the bus code to bind actual devices to the driver; there are two mechanisms which can be used for that purpose. The first is the id_table argument; the relevant structure is:

    struct platform_device_id {        char name[PLATFORM_NAME_SIZE];        kernel_ulong_t driver_data;    };If an ID table is present, the platform bus code will scan through it every time it has to find a driver for a new platform device. If the device's name matches the name in an ID table entry, the device will be given to the driver for management; a pointer to the matching ID table entry will be made available to the driver as well. As it happens, though, most platform drivers do not provide an ID table at all; they simply provide a name for the driver itself in the driver field. As an example, the i2c-gpio driver turns two GPIO lines into an i2c bus; it sets itself up as a platform device with:

    static struct platform_driver i2c_gpio_driver = {        .driver                = {                .name        = "i2c-gpio",                .owner        = THIS_MODULE,        },        .probe                = i2c_gpio_probe,        .remove                = __devexit_p(i2c_gpio_remove),    };
With this setup, any device identifying itself as "i2c-gpio" will be bound to this driver; no ID table is needed.
Platform drivers make themselves known to the kernel with:

    int platform_driver_register(struct platform_driver *driver);
As soon as this call succeeds, the driver's probe() function can be called with new devices. That function gets as an argument a platform_device pointer describing the device to be instantiated:

    struct platform_device {        const char        *name;        int                id;        struct device        dev;        u32                num_resources;        struct resource        *resource;        const struct platform_device_id        *id_entry;        /* Others omitted */    };
The dev structure can be used in contexts where it is needed - the DMA mapping API, for example. If the device was matched using an ID table entry, id_entry will point to the specific entry matched. The resource array can be used to learn where various resources, including memory-mapped I/O registers and interrupt lines, can be found. There are a number of helper functions for getting data out of the resource array; these include:

    struct resource *platform_get_resource(struct platform_device *pdev,                                            unsigned int type, unsigned int n);    struct resource *platform_get_resource_byname(struct platform_device *pdev,                                           unsigned int type, const char *name);    int platform_get_irq(struct platform_device *pdev, unsigned int n);
The "n" parameter says which resource of that type is desired, with zero indicating the first one. Thus, for example, a driver could find its second MMIO region with:

    r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
Assuming the probe() function finds the information it needs, it should verify the device's existence to the extent possible, register the "real" devices associated with the platform device, and return zero.

Platform devices
So now we have a driver for a platform device, but no actual devices yet. As was noted at the beginning, platform devices are inherently not discoverable, so there must be another way to tell the kernel about their existence. That is typically done with the creation of a static platform_device structure providing, at a minimum, a name which is used to find the associated driver. So, for example, a simple (fictional) device might be set up this way:

    static struct resource foomatic_resources[] = {        {                .start        = 0x10000000,                .end        = 0x10001000,                .flags        = IORESOURCE_MEM,                .name        = "io-memory"        },        {                .start        = 20,                .end        = 20,                .flags        = IORESOURCE_IRQ,                .name        = "irq",        }    };    static struct platform_device my_foomatic = {        .name                 = "foomatic",        .resource        = foomatic_resources,        .num_resources        = ARRAY_SIZE(foomatic_resources),    };
These declarations describe a "foomatic" device with a one-page MMIO region starting at 0x10000000 and using IRQ 20. The device is made known to the system with:

    int platform_device_register(struct platform_device *pdev);
Once both a platform device and an associated driver have been registered, the driver's probe() function will be called and the device will be instantiated. Registration of device and driver are usually done in different places and can happen in either order. A call to platform_device_unregister() can be used to remove a platform device.

Platform data
The above information is adequate to instantiate a simple platform device, but many devices are more complex than that. Even the simple i2c-gpio driver described above needs two additional pieces of information: the numbers of the GPIO lines to be used as i2c clock and data lines. The mechanism used to pass this information is called "platform data"; in short, one defines a structure containing the specific information needed and passes it in the platform device's dev.platform_data field.
With the i2c-gpio example, a full configuration looks like this:

    #include     static struct i2c_gpio_platform_data my_i2c_plat_data = {        .scl_pin        = 100,        .sda_pin        = 101,    };    static struct platform_device my_gpio_i2c = {        .name                = "i2c-gpio",        .id                = 0,        .dev = {                .platform_data = &my_i2c_plat_data,        }    };
When the driver's probe() function is called, it can fetch the platform_data pointer and use it to obtain the rest of the information it needs.
Not everybody in the kernel community is enamored with platform devices; they seem like a bit of a hack used to encode information about specific hardware platforms into the kernel. Additionally, the platform data mechanism lacks any sort of type checking; drivers must simply assume that they have been passed a structure of the expected type. Even so, platform devices are heavily used, and that's unlikely to change, though the means by which they are created and discovered is changing. The way of the future appears to be device trees, which will be described in the following article.
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 
 

回复

854

帖子

0

TA的资源

五彩晶圆(中级)

5
 
    struct platform_device_id {        char name[PLATFORM_NAME_SIZE];        kernel_ulong_t driver_data;    };If an ID table is present, the platform bus code will scan through it every time it has to find a driver for a new platform device. If the device's name matches the name in an ID table entry, the device will be given to the driver for management; a pointer to the matching ID table entry will be made available to the driver as well. As it happens, though, most platform drivers do not provide an ID table at all; they simply provide a name for the driver itself in the driver field. As an example, the i2c-gpio driver turns two GPIO lines into an i2c bus; it sets itself up as a platform device with:

这里面说明platform_device_id 放置一些驱动名字,然后会自动匹配的, 有些驱动根本没有platform_device_id 这个东西,所以这次见到我也很诧异。
但是这个触摸屏幕驱动既有driver name 又有platform_device_id 咋回事?!!

static struct platform_device_id s3cts_driver_ids[] = {
        { "s3c2410-ts", 0 },
        { "s3c2440-ts", 0 },
        { "s3c64xx-ts", FEAT_PEN_IRQ },
        { }
};
MODULE_DEVICE_TABLE(platform, s3cts_driver_ids);

static struct platform_driver s3c_ts_driver = {
        .driver         = {
                .name   = "samsung-ts",
                .owner  = THIS_MODULE,
#ifdef CONFIG_PM
                .pm        = &s3c_ts_pmops,
#endif
        },
        .id_table        = s3cts_driver_ids,
        .probe                = s3c2410ts_probe,
        .remove                = __devexit_p(s3c2410ts_remove),
};


这个是怎么回事的呢?
难道前面的.name   = "samsung-ts", 这个好像是无效的一样。
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表