Platform device/
driver
HOW TO START?
J.M. Seo
 Meaning: Platform devices are devices that typically appear as autonomous
entities in the system. This includes legacy port-based devices and host
bridges to peripheral buses, and most controllers integrated into system-on-
chip platforms. What they usually have in common is direct addressing from
a CPU …… <From kernel.org>
 Simply, they are built-in devices in SoC. They are wired into SoC, so we
cannot remove them. And we cannot us them as Plug & Play devices.
Typically, many peripheral interface buses, such as I2C, SPI, I2S, and so on
are included.
PLATFORM DEVICE?
 Platform drivers follow the standard driver model convention, where
discovery/enumeration is handled outside the drivers, and drivers provide
probe() and remove() methods. <from kernel.org>
 Again, simply, it is to handle platform devices.
 Their first purpose is to notify the existence of a devices to Linux kernel.
 The second thing is to allocate all resources to operate a device.
 For it, probe() is needed to create. The function should be able to register
the device as one of platform buses in Linux kernel.
PLATFORM DRIVER?
 That is the first step that we have to
do for platform device.
 Actually, That is one of callback
functions in “struct platform_driver”
 We just see only probe(). This is
because the structure covers all of the
steps from Registrations to Power
Management.
PROVE()?
 Let’s make skeleton platform device driver.
 In order to implement a probe function
easy, we will use the way using Linux kernel
module.
 We need to put two functions,
module_init() and module_exit() in our
source file first.
 Then, create our own functions that
module_xxx()s enable to contain them.
 When we build the driver and load it to the
kernel, it will do nothing, because we have
not made prove() yet.
TO CALL PROVE()- 1ST STEP
module_init(char_skel_init);
module_exit(char_skel_exit);
static int __init char_skel_init(void)
{
pr_info(“%s: enter...n“, __func__);
}
static void __exit char_skel_exit(void)
{
pr_info (“%s: enter...n“, __func__);
}
 Make a new instance data with a
platform_driver structure.
 A platform_driver structure are composed
of various elements. But, now, focus on only
two elements, ‘probe’ and ‘driver.name’.
 ‘name’ field is very important. The kernel
will check if it has a platform device that has
the same name. If so, the kernel will call our
probe(), once the driver is loaded.
 How can we make the kernel have platform
device that has a element named
“char_skel”?
TO CALL PROVE()- 2ND STEP
static struct platform_driver char_skel_driver = {
.probe = char_skel_probe,
.driver = {
.name = "char_skel",
},
};
static int char_skel_probe(struct platform_device
*pdev)
{
pr_info(“%s: enter...n“, __func__);
return 0;
}
 Actually, finding a platform_driver
that fit a platform_device with “name”
is old style. In this case, in order for
the kernel to have the platform device
that has same name, we need to add
our platform device in the a board-
specific file. Unfortunately, many
board-specific files are disappearing
now.
 So, we have to use DT. Just add new
node in current dts file. Then, build
current dtb again.
TO CALL PROVE()- 3RD STEP - 1
/ {
char_skel {
compatible = "my,char-skel";
};
};
 And add a new instance made of
objects called “of_device_id”. Where, the
name of compatible should be same as
the name of compatible in DTS.
 Then, give the instance a new field
named “of_match_table” in
platform_driver container.
 In summary,
1. Make a new node to describe our
driver. It should include the name of
compatible decided.
2. Create of_match_table. Then, add
the instance as a new field in our
platform driver container.
TO CALL PROVE()- 3RD STEP - 2
static struct platform_driver char_skel_driver = {
.probe = char_skel_probe,
.driver = {
.name = "char_skel",
.of_match_table = char_skel_of_match_table,
},
};
static const struct of_device_id char_skel_of_match_table[] = {
{
.compatible = "my,char-skel",
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, char_skel_of_match_table);
 When the driver module is loaded
by using “insmod”, we can see
that the probe() is called.
TO CALL PROVE()- DONE
# insmod ch_skel.ko
[ 19.294872] char_skel_init: enter
[ 19.299144] char_skel_probe: enter...
 Allocate memory space to store a
device driver private data. It will be
shared with each function in our driver.
Why? Almost all of the functions we
make will be called by the kernel. It
happens outside our context and driver.
 Take resources
 IRQ number
 Memory address range dedicated.
 Clock
 GPIO
 Etc…
 To get resource, we must write the
details of resources in the current DTS
file in advance.
WHAT TO DO IN PROVE() 1ST
platform_get_irq(pdev, 0);
devm_ioremap_resource(&pdev->dev, res);
devm_clk_get(&pdev->dev, "int-clk");
My_drv_data = devm_kzalloc(&pdev->dev,
sizeof(*my_drv_data), GFP_KERNEL);
platform_set_drvdata(pdev, my_drv_data);
 Start irq service routine for the
driver.
 Register again.
 Again? What? We just registered
this as just platform driver so far.
 We have to register current driver
with purpose. According to a
device’s purpose, the kernel
provides various functions to
register.
WHAT TO DO IN PROVE() 2ND
devm_spi_register_master(&pdev->dev, master);
…
usb_register_dev(interface, &skel_class);
…
mfd_add_devices(…)
…
devm_request_irq(…)
 Actually, to make a specific driver, we don’t need to make it as
platform driver. However, It seems helpful to understand the a
hardware feature that we use and make us study it more.
 After proving, the direction of development will follow along the
driver’s goal.
 This slides just only said that how to start developing of a
device driver.
Thank you.
THAT’S IT

Platform Device/Driver

  • 1.
  • 2.
     Meaning: Platformdevices are devices that typically appear as autonomous entities in the system. This includes legacy port-based devices and host bridges to peripheral buses, and most controllers integrated into system-on- chip platforms. What they usually have in common is direct addressing from a CPU …… <From kernel.org>  Simply, they are built-in devices in SoC. They are wired into SoC, so we cannot remove them. And we cannot us them as Plug & Play devices. Typically, many peripheral interface buses, such as I2C, SPI, I2S, and so on are included. PLATFORM DEVICE?
  • 3.
     Platform driversfollow the standard driver model convention, where discovery/enumeration is handled outside the drivers, and drivers provide probe() and remove() methods. <from kernel.org>  Again, simply, it is to handle platform devices.  Their first purpose is to notify the existence of a devices to Linux kernel.  The second thing is to allocate all resources to operate a device.  For it, probe() is needed to create. The function should be able to register the device as one of platform buses in Linux kernel. PLATFORM DRIVER?
  • 4.
     That isthe first step that we have to do for platform device.  Actually, That is one of callback functions in “struct platform_driver”  We just see only probe(). This is because the structure covers all of the steps from Registrations to Power Management. PROVE()?
  • 5.
     Let’s makeskeleton platform device driver.  In order to implement a probe function easy, we will use the way using Linux kernel module.  We need to put two functions, module_init() and module_exit() in our source file first.  Then, create our own functions that module_xxx()s enable to contain them.  When we build the driver and load it to the kernel, it will do nothing, because we have not made prove() yet. TO CALL PROVE()- 1ST STEP module_init(char_skel_init); module_exit(char_skel_exit); static int __init char_skel_init(void) { pr_info(“%s: enter...n“, __func__); } static void __exit char_skel_exit(void) { pr_info (“%s: enter...n“, __func__); }
  • 6.
     Make anew instance data with a platform_driver structure.  A platform_driver structure are composed of various elements. But, now, focus on only two elements, ‘probe’ and ‘driver.name’.  ‘name’ field is very important. The kernel will check if it has a platform device that has the same name. If so, the kernel will call our probe(), once the driver is loaded.  How can we make the kernel have platform device that has a element named “char_skel”? TO CALL PROVE()- 2ND STEP static struct platform_driver char_skel_driver = { .probe = char_skel_probe, .driver = { .name = "char_skel", }, }; static int char_skel_probe(struct platform_device *pdev) { pr_info(“%s: enter...n“, __func__); return 0; }
  • 7.
     Actually, findinga platform_driver that fit a platform_device with “name” is old style. In this case, in order for the kernel to have the platform device that has same name, we need to add our platform device in the a board- specific file. Unfortunately, many board-specific files are disappearing now.  So, we have to use DT. Just add new node in current dts file. Then, build current dtb again. TO CALL PROVE()- 3RD STEP - 1 / { char_skel { compatible = "my,char-skel"; }; };
  • 8.
     And adda new instance made of objects called “of_device_id”. Where, the name of compatible should be same as the name of compatible in DTS.  Then, give the instance a new field named “of_match_table” in platform_driver container.  In summary, 1. Make a new node to describe our driver. It should include the name of compatible decided. 2. Create of_match_table. Then, add the instance as a new field in our platform driver container. TO CALL PROVE()- 3RD STEP - 2 static struct platform_driver char_skel_driver = { .probe = char_skel_probe, .driver = { .name = "char_skel", .of_match_table = char_skel_of_match_table, }, }; static const struct of_device_id char_skel_of_match_table[] = { { .compatible = "my,char-skel", }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, char_skel_of_match_table);
  • 9.
     When thedriver module is loaded by using “insmod”, we can see that the probe() is called. TO CALL PROVE()- DONE # insmod ch_skel.ko [ 19.294872] char_skel_init: enter [ 19.299144] char_skel_probe: enter...
  • 10.
     Allocate memoryspace to store a device driver private data. It will be shared with each function in our driver. Why? Almost all of the functions we make will be called by the kernel. It happens outside our context and driver.  Take resources  IRQ number  Memory address range dedicated.  Clock  GPIO  Etc…  To get resource, we must write the details of resources in the current DTS file in advance. WHAT TO DO IN PROVE() 1ST platform_get_irq(pdev, 0); devm_ioremap_resource(&pdev->dev, res); devm_clk_get(&pdev->dev, "int-clk"); My_drv_data = devm_kzalloc(&pdev->dev, sizeof(*my_drv_data), GFP_KERNEL); platform_set_drvdata(pdev, my_drv_data);
  • 11.
     Start irqservice routine for the driver.  Register again.  Again? What? We just registered this as just platform driver so far.  We have to register current driver with purpose. According to a device’s purpose, the kernel provides various functions to register. WHAT TO DO IN PROVE() 2ND devm_spi_register_master(&pdev->dev, master); … usb_register_dev(interface, &skel_class); … mfd_add_devices(…) … devm_request_irq(…)
  • 12.
     Actually, tomake a specific driver, we don’t need to make it as platform driver. However, It seems helpful to understand the a hardware feature that we use and make us study it more.  After proving, the direction of development will follow along the driver’s goal.  This slides just only said that how to start developing of a device driver. Thank you. THAT’S IT