Questions About Embedded Linux Device Driver by Linux Newbie

Embedded Linux Newbie Questions

1) Does the kernel depend on the dtb/dts files when compiling? I thought that the kernel only needs to know the chip architecture (i.e. arm) and the dtb file is loaded by the boot loader (uBoot [sic]) so therefore the kernel only needs to load its drivers which are configured by the dtb file.

The Linux kernel is compiled without any dependency on the Device Tree.

The compilation of the kernel does depend on the chip architecture, but which code modules that are compiled depends on the board configuration(s) and feature selection.

BTW it's U-Boot for Universal Boot, not microBoot.

2) Mixing and matching: I'm under the impression that I can mix and match any combination of boot loader, dtb, kernel, rootfs, and modules given the following

kernel: must know which chip it is compiled for

dtb: must know the board details and chip, i.e. how much ram, configure a GPIO for SPI
boot loader: must know the chip and uEnv.txt must have params for the kernel and dtb location

rootfs: completely independent

modules: must be compiled with the specific version of kernel

Essentially correct, but typically one doesn't go overboard in trying to "mix-n-match". There are often optimal or preferred (or at least appropriate) choices.

By "rootfs" I'm assuming you mean type of filesystem for the rootfs, rather some image of a rootfs. (See Addendum below.)

3) Drivers: If I want to load a SPI driver do I need anything specific or

There are two types of "SPI driver", the master and protocol.

The SPI master driver is for the SPI controller chip that serves as the one interface master. This is usually a platform driver and not have a device node in /dev.

For each SPI slave device there must be a protocol driver. This driver will typically have a device node in /dev.

will the kernel know how to operate this because the dtb file setup the required registers?

The Device Tree must specify which driver is for which device and any/all resources allocated/assigned to each device.

The dtb file does not "setup" anything. It's only configuration data; there is no executable code. A device driver, typically during its probe or initialization phase, is responsible for acquiring/allocating its resources.

4) Modules: Are these just dependent on the kernel or do they need to know something about the chip and board?

Your use of "modules" is ambiguous. Source code files are sometimes referred to as "modules". Presumably you really mean loadable kernel modules.

Although most people associate kernel modules (only) with device drivers, other kernel services such as filesystems and network protocol handlers can also be built as modules.
The primary rationale for a kernel module versus static linkage (i.e. built in the kernel) is for runtime configurability (which in turn improves memory efficiency). Optional features, services and drivers can be left out of the kernel that is booted, but can still be loaded later when needed.

Loadable modules are "dependent" on the kernel simply because of linking requirements for proper execution. The degree of "chip and board knowledge" obviously depends on the functionality of the module, just like any other piece of kernel code.

Addendum

when I say rootfs I am referring to a prebuilt rootfs

A kernel image and (prebuilt) rootfs image are not "completely independent".

The executable binaries and the shared libraries in the rootfs image must be compatible with the kernel features. More significantly, since kernel loadable modules are installed in the rootfs and not with the kernel image, and these modules can be strictly tied to a specific build of a kernel version, it makes sense to pair a kernel image with a rootfs image.

Writing device driver for embedded boards

What i understood for now is, product owner has already written some functions to reach peripheral hardware and all i have to do is reaching them with calling some special functions using its .c files.
Blockquote

Your understanding is partly correct - the board vendor has already written drivers (functions for reading/writing the hardware registers). However, it is not as simple as just linking against the c files of the drivers.

In Linux, the mechanism for using these drivers (driver API) varies depending on the use-case. The drivers can be accessed from both the user and kernel space. Both of these spaces have different APIs to interact with drivers. There is a lot of layering (abstraction) in the Linux kernel drivers and a large part of the effort is getting familiar with the all the abstraction levels involved.

While using the driver from userspace, the most common API is to use the device files representing a device and doing file operations on it. For example, a usb-to-serial UART is commonly represented by device file /dev/ttyUSB0 and all the interaction with the driver goes through this device file. You can search for writing character drivers on Linux to get more understanding on this. In essence, your Linux kernel driver needs to create a device file and you need to map the operations done on this device file (open, read, write, close, ioctl) to the device hardware-specific functions in your driver.

Linux builds upon that to create specific driver subsystems. For example, the Linux framebuffer subsystem, which is commonly used to draw graphics on the display. It is also a device file, but has operations that are common for all of the framebuffer devices. The device-specific functions will go into another separate driver that contains hardware-specific bits. The goal is simple, to keep the generic reusable code and hardware-specific bits separate.

If you want to by-pass the userspace API and interface with some other kernel code or driver directly, you need to write a kernel module that runs in the kernel space and here, you can link against functions exported by the common kernel driver from vendor. This was just to give you a basic idea, there are a lot of underlying details that will be unveiled once you actually start writing some code interfacing with drivers. I would suggest starting with the simple character driver. You can follow this tutorial

Linux device driver with optional multiple platform driver interfaces

For chips providing several interface types, standard practice is to provide core driver and interface-specific frontends for it.

Several examples could be found e.g. in sound/soc/codecs/: pcm179x.c / pcm179x-i2c.c / pcm179x-spi.c and others.

This is not (yet?) done for ssd1307.

What is the difference between a Linux platform driver and normal device driver?

Your references are good but lack a definition of what is a platform device. There is one on LWN. What we can learn from this page:

  1. Platform devices are inherently not discoverable, i.e. the hardware cannot say "Hey! I'm present!" to the software. Typical examples are i2c devices, kernel/Documentation/i2c/instantiating-devices states:

    Unlike PCI or USB devices, I2C devices are not enumerated at the hardware level (at run time).
    Instead, the software must know (at compile time) which devices are connected on each I2C bus segment.
    So USB and PCI are not platform devices.

  2. Platform devices are bound to drivers by matching names,

  3. Platform devices should be registered very early during system boot. Because they are often critical to the rest of the system (platform) and its drivers.

So basically, the question "is it a platform device or a standard device?" is more a question of which bus it uses. To work with a particular platform device, you have to:

  1. register a platform driver that will manage this device. It should define a unique name,
  2. register your platform device, defining the same name as the driver.

Platform driver is for those devices that are on chip.

Not true (in theory, but true in practice). i2c devices are not onChip, but are platform devices because they are not discoverable. Also we can think of onChip devices which are normal devices. Example: an integrated PCI GPU chip on a modern x86 processor. It is discoverable, thus not a platform device.

Normal device driver are for those that are interfaced to the processor chip. before coming across one i2c driver.

Not true. Many normal devices are interfaced to the processor, but not through an i2c bus. Example: a USB mouse.

[EDIT] In your case, have a look to drivers/usb/host/ohci-pnx4008.c, which is a USB host controller platform device (Here the USB host controller is not discoverable, whereas USB devices, which will connect to it, are). It is a platform device registered by the board file (arch/arm/mach-pnx4008/core.c:pnx4008_init). And within its probe function, it registers its i2c device to the bus with i2c_register_driver. We can infer that the USB Host controller chipset talks to the CPU through an i2c bus.

Why that architecture? Because on one hand, this device can be considered a bare i2c device providing some functionalities to the system. On the other hand, it is a USB Host capable device. It needs to register to the USB stack (usb_create_hcd). So probing only i2c will be insufficient. Have a look to Documentation/i2c/instantiating-devices.

Writing Device Driver in Linux

1. As long as the peripheral is interfaced similarly to the SoC(i.e. uses the same hardware interface on both the platforms), the same driver can be used on both x86 and ARM. This is the advantage of developing modular drivers independent from the Linux kernel core.


2. If your particular peripheral does NOT exist in the current address map(/proc/iomem) then it could mean one of two possibilities :

  • The device driver is not loaded yet.
  • The device uses other form of addressing (NOT memory mapped I/O)

Any additional info about the peripheral? How is it connected to the SoC?


3. A device-tree in the Linux kernel is used to describe the numerous hardware (both-on-chip and peripherals), their inter-connectivity and the basic params applicable for their proper configuration and initialisation on a specific platform/board for which the device-tree is written.

Essentially it performs the same functions and the "board-file" found in current Linux kernel. It also reduces the dependency of bootargs for initial configuration as the same can be provided in the device-tree. More info on device trees.



Related Topics



Leave a reply



Submit