嵌入式学习之Linux驱动(第六期_平台总线)

105 阅读3分钟

平台总线

平台总线模型

物理总线: I2C SPI

平台总线是Linux系统虚拟出来的总线

平台总线模型的使用

image.png

image.png

平台设备驱动

image.png

struct platform_device {
	const char	*name; // device.c 和 driver.c 下的名称要一致才能匹配成功
	int		id; // 设置成-1则不会生成后缀
	bool		id_auto;
	struct device	dev;
	u32		num_resources;
	struct resource	*resource;

	const struct platform_device_id	*id_entry;
	char *driver_override; /* Driver name to force a match */

	/* MFD cell pointer */
	struct mfd_cell *mfd_cell;

	/* arch specific additions */
	struct pdev_archdata	archdata;
};

// include/linux/device.h
struct device {
	struct device		*parent;

	struct device_private	*p;

	struct kobject kobj;
	const char		*init_name; /* initial name of the device */
	const struct device_type *type;
        //...
        void	(*release)(struct device *dev);
        //...
}

// include/linux/ioport.h
/*
 * Resources are tree-like, allowing
 * nesting etc..
 */
struct resource {
	resource_size_t start;
	resource_size_t end;
	const char *name;
	unsigned long flags; // 资源类型
	struct resource *parent, *sibling, *child;
};

ls /sys/bus/platform/devices/

注册总线成功后,会显示在此目录下

资源类型

include/linux/ioport.h

/*
 * IO resources have these defined flags.
 */
#define IORESOURCE_BITS		0x000000ff	/* Bus-specific bits */

#define IORESOURCE_TYPE_BITS	0x00001f00	/* Resource type */
#define IORESOURCE_IO		0x00000100	/* PCI/ISA I/O ports */
#define IORESOURCE_MEM		0x00000200
#define IORESOURCE_REG		0x00000300	/* Register offsets */
#define IORESOURCE_IRQ		0x00000400
#define IORESOURCE_DMA		0x00000800
#define IORESOURCE_BUS		0x00001000

#define IORESOURCE_PREFETCH	0x00002000	/* No side effects */
#define IORESOURCE_READONLY	0x00004000
#define IORESOURCE_CACHEABLE	0x00008000
#define IORESOURCE_RANGELENGTH	0x00010000
#define IORESOURCE_SHADOWABLE	0x00020000

#define IORESOURCE_SIZEALIGN	0x00040000	/* size indicates alignment */
#define IORESOURCE_STARTALIGN	0x00080000	/* start field is alignment */

#define IORESOURCE_MEM_64	0x00100000
#define IORESOURCE_WINDOW	0x00200000	/* forwarded by bridge */
#define IORESOURCE_MUXED	0x00400000	/* Resource is software muxed */

#define IORESOURCE_EXCLUSIVE	0x08000000	/* Userland may not map this resource */
#define IORESOURCE_DISABLED	0x10000000
#define IORESOURCE_UNSET	0x20000000	/* No address assigned yet */
#define IORESOURCE_AUTO		0x40000000
#define IORESOURCE_BUSY		0x80000000	/* Driver has marked this resource busy */

image.png

相关函数

image.png

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>

static struct resource my_resource[] = {
    [0] = {
        .start = 0xFD660000,
        .end = 0xFD660004,
        .flags = IORESOURCE_MEM},
    [1] = {.start = 13, .end = 13, .flags = IORESOURCE_IRQ},
};

void my_release(struct device *dev)
{
    printk("my_release");
}

struct platform_device my_device
{
    .name = "my_device",
    .id = -1,
    .resource = my_resource,
    .num_resources = ARRAY_SIZE(my_resource),
    .dev = {
        .release = my_release,
    }
};

static int dev_init(void)
{
    platform_device_register(&my_device);
    printk("hello init");
    return 0;
}

static void dev_exit(void)
{
    platform_device_unregister(&my_device);
    printk("hello bye");
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("MCC");
MODULE_VERSION("V1.0");

软件驱动部分

image.png

// include/linux/platform_device.h
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;
	bool prevent_deferred_probe;
};

image.png

案例代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>

int my_probe(struct platform_device *p)
{
    printk("my_probe");
    return 0;
}

int my_remove(struct platform_device *p)
{
    printk("my_remove");
    return 0;
}

struct platform_driver my_driver
{
    .probe = my_probe,
    .remove = my_remove,
    .driver = {
        .name = "my_device",
        .owner = THIS_MODULE},
};

static int dev_init(void)
{
    platform_driver_register(&my_driver);
    printk("hello init");
    return 0;
}

static void dev_exit(void)
{
    platform_driver_unregister(&my_driver);
    printk("hello bye");
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("MCC");
MODULE_VERSION("V1.0");

编写probe函数

image.png

image.png

int my_probe(struct platform_device *p)
{
    struct resource *my = platform_get_resource(p, IORESOURCE_IRQ, 0);
    printk("my_probe start=%ld\n", my->start);
    return 0;
}

LED 驱动