What's the structure member 'pm' in the driver structure? - linux

What's 'pm' and 'of_match_table' in the following spi driver code
static struct platform_driver omap2_mcspi_driver = {
.driver = {
.name = "omap2_mcspi",
.owner = THIS_MODULE,
.pm = &omap2_mcspi_pm_ops,
.of_match_table = omap_mcspi_of_match,
},
.probe = omap2_mcspi_probe,
.remove = omap2_mcspi_remove,
};

First, take a look on From where platform device gets it name. You can find more details on ACPI based device enumeration.

Related

Linux I2C Kernel Driver

I have a requirement to create a Linux Kernel Driver to interface with a bunch of MCU's over I2C, through an Interface Board. Because they would be many in number, i.e around 1-18, we are utilising a NXP / TI I2C Multiplexer.
I have imported the NXP / TI I2C Multiplexer kernel driver and have incorporated the same in the DTS file. I have been successfully able to list all the I2C Multiplexers as different i2c-x nodes.
The MCU's all are using the same Address 0x08. And I create a kernel driver which creates a hwmon + sysfs interface for it.
However, the driver upon insmod only triggers __init function. And does not bother with probe().
Upon referring to many documentations I was able to trigger probe function only when am inserting
static struct i2c_board_info xxxx_i2c_devices[] = {
{
I2C_BOARD_INFO("xxxx", 0x08),
},
};
And its corresponding
i2c_register_board_info(0, xxxx_i2c_devices, ARRAY_SIZE(xxxx_i2c_devices));
However, this creates only one instance in HWMON and not several as I imagined it to be. I have referred https://www.kernel.org/doc/Documentation/i2c/instantiating-devices
Without the changes in board init, I tried to utilize the Method 3, however kernel doesn't even call the probe() and detect function(), only the __init function of the driver.
Am following the driver -
https://github.com/1119553797/sprd-kernel-common/blob/sprdb2g_gonk4.0/drivers/hwmon/w83l785ts.c
Would post the entire kernel driver if needed, for reference am using the Kernel 3.0.8, a custom board using board level changes to the same mentioned kernel.
Ok, after extensive googling and patching different methods heres a workaround.
First and foremost in the DTS, we can assign the I2C address in the Mux addressing directly. For .e.g.
i2c#0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
adc0: nau7802#2a {
compatible = "nuvoton,nau7802";
reg = <0x2a>;
nuvoton,vldo = <3000>;
};
};
i2c#1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
adc1: nau7802#2a {
compatible = "nuvoton,nau7802";
reg = <0x2a>;
nuvoton,vldo = <3000>;
};
};
i2c#2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
adc2: nau7802#2a {
compatible = "nuvoton,nau7802";
reg = <0x2a>;
nuvoton,vldo = <3000>;
};
};
Then in the driver, in order to identify with the VendorID,ProductID structure as in the above example "nuvoton,nau7802", we have to make the following changes :-
static const struct i2c_device_id nau7802_i2c_id[] = {
{ "nau7802", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id);
static const struct of_device_id nau7802_dt_ids[] = {
{ .compatible = "nuvoton,nau7802" },
{},
};
MODULE_DEVICE_TABLE(of, nau7802_dt_ids);
static struct i2c_driver nau7802_driver = {
.probe = nau7802_probe,
.remove = nau7802_remove,
.id_table = nau7802_i2c_id,
.driver = {
.name = "nau7802",
.of_match_table = nau7802_dt_ids,
},
};
The part "adc1" etc can be simply skipped. "MODULE_DEVICE_TABLE(of," is meant to be device_tree information, from what I could gather.
Please do let me know if you find a better method which does not require a DTS & board _init changes.

How devices in device tree and platform drivers were connected

I read some articles about this topic. but none of them describes the details.
What I know is:
declare "compatible" property in Device tree:
gpio0: gpio#44e07000 {
compatible = "ti,omap4-gpio";
...
};
and make the connection to platform driver by
static const struct of_device_id omap_gpio_match[] = {
{
.compatible = "ti,omap4-gpio",
},
{ },
};
...
static struct platform_driver omap_gpio_driver = {
.probe = omap_gpio_probe,
.driver = {
.name = "omap_gpio",
.pm = &gpio_pm_ops,
.of_match_table = of_match_ptr(omap_gpio_match),
},
};
and as a result, of_match_table will be used to match the compatible property declared in Device Tree.
and the match action performed in platform_match (drivers/base/platform.c) function. I doubt this because the I greped reference of of_match_table and the only probable result located in of_device_get_match_data (drivers/of/device.c) function.
~/wk/linux$ find . -name '*.c' | xargs grep '\<of_match_table\>' | grep -v -E 'of_match_table\s+='
./drivers/dma/sirf-dma.c: (of_match_device(op->dev.driver->of_match_table,
./drivers/macintosh/macio_asic.c: const struct of_device_id * matches = drv->of_match_table;
./drivers/macintosh/macio_asic.c: match = of_match_device(drv->driver.of_match_table, dev);
./drivers/nvmem/mxs-ocotp.c: match = of_match_device(dev->driver->of_match_table, dev);
./drivers/reset/sti/reset-syscfg.c: match = of_match_device(dev->driver->of_match_table, dev);
./drivers/mtd/devices/m25p80.c: * matching for .of_match_table
./drivers/soc/rockchip/pm_domains.c: match = of_match_device(dev->driver->of_match_table, dev);
./drivers/phy/phy-rockchip-usb.c: match = of_match_device(dev->driver->of_match_table, dev);
./drivers/acpi/bus.c: * #of_match_table: List of device IDs to match against.
./drivers/acpi/bus.c: const struct of_device_id *of_match_table)
./drivers/acpi/bus.c: if (!of_match_table || !of_compatible)
./drivers/acpi/bus.c: for (id = of_match_table; id->compatible[0]; id++)
./drivers/acpi/bus.c: drv->of_match_table);
./drivers/acpi/bus.c: drv->acpi_match_table, drv->of_match_table);
./drivers/pci/host/pcie-hisi.c: match = of_match_device(driver->of_match_table, &pdev->dev);
./drivers/pinctrl/stm32/pinctrl-stm32.c: match = of_match_device(dev->driver->of_match_table, dev);
./drivers/of/device.c: match = of_match_device(dev->driver->of_match_table, dev);
./drivers/mfd/axp20x.c: of_id = of_match_device(dev->driver->of_match_table, dev);
./drivers/gpu/drm/armada/armada_crtc.c: match = of_match_device(dev->driver->of_match_table, dev);
./arch/powerpc/kernel/ibmebus.c: ibmebus_create_devices(drv->driver.of_match_table);
./arch/powerpc/kernel/ibmebus.c: const struct of_device_id *matches = drv->of_match_table;
./sound/soc/qcom/lpass-cpu.c: match = of_match_device(dev->driver->of_match_table, dev);
But this function is not used in some common modules.
~/wk/linux$ find . -name '*.c' | xargs grep of_device_get_match_data
./drivers/dma/sh/shdmac.c: pdata = of_device_get_match_data(&pdev->dev);
./drivers/dma/tegra210-adma.c: cdata = of_device_get_match_data(&pdev->dev);
./drivers/dma/tegra20-apb-dma.c: cdata = of_device_get_match_data(&pdev->dev);
./drivers/usb/host/xhci-tegra.c: tegra->soc = of_device_get_match_data(&pdev->dev);
./drivers/usb/phy/phy-msm-usb.c: pdata->phy_type = (enum msm_usb_phy_type)of_device_get_match_data(&pdev->dev);
./drivers/mtd/spi-nor/fsl-quadspi.c: q->devtype_data = of_device_get_match_data(dev);
./drivers/mtd/nand/qcom_nandc.c: dev_data = of_device_get_match_data(dev);
./drivers/mtd/nand/atmel_nand.c: of_device_get_match_data(host->dev);
./drivers/rtc/rtc-sunxi.c: chip->data_year = of_device_get_match_data(&pdev->dev);
./drivers/spi/spi-mpc512x-psc.c: mps->type = (int)of_device_get_match_data(dev);
./drivers/watchdog/mpc8xxx_wdt.c: wdt_type = of_device_get_match_data(&ofdev->dev);
./drivers/phy/phy-exynos-mipi-video.c: phy_dev = of_device_get_match_data(dev);
./drivers/phy/phy-sun4i-usb.c: data->cfg = of_device_get_match_data(dev);
./drivers/pci/host/pci-imx6.c: (enum imx6_pcie_variants)of_device_get_match_data(&pdev->dev);
./drivers/pci/host/pcie-qcom.c: pcie->ops = (struct qcom_pcie_ops *)of_device_get_match_data(dev);
./drivers/i2c/busses/i2c-rcar.c: priv->devtype = (enum rcar_i2c_type)of_device_get_match_data(dev);
./drivers/i2c/busses/i2c-tegra.c: i2c_dev->hw = of_device_get_match_data(&pdev->dev);
./drivers/tty/serial/imx.c: sport->devdata = of_device_get_match_data(&pdev->dev);
./drivers/gpio/gpio-mpc8xxx.c: of_device_get_match_data(&pdev->dev);
./drivers/gpio/gpio-tegra.c: config = of_device_get_match_data(&pdev->dev);
./drivers/clk/clk-palmas.c: match_data = of_device_get_match_data(&pdev->dev);
./drivers/input/misc/pmic8xxx-pwrkey.c: pwrkey->shutdown_fn = of_device_get_match_data(&pdev->dev);
./drivers/input/touchscreen/edt-ft5x06.c: chip_data = of_device_get_match_data(&client->dev);
./drivers/pinctrl/sh-pfc/core.c: info = of_device_get_match_data(&pdev->dev);
./drivers/thermal/rcar_thermal.c: unsigned long of_data = (unsigned long)of_device_get_match_data(dev);
./drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c: data = of_device_get_match_data(&pdev->dev);
./drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c: data = of_device_get_match_data(&pdev->dev);
./drivers/net/ethernet/renesas/sh_eth.c: mdp->cd = (struct sh_eth_cpu_data *)of_device_get_match_data(&pdev->dev);
./drivers/net/ethernet/renesas/ravb_main.c: chip_id = (enum ravb_chip_id)of_device_get_match_data(&pdev->dev);
./drivers/of/device.c:const void *of_device_get_match_data(const struct device *dev)
./drivers/of/device.c:EXPORT_SYMBOL(of_device_get_match_data);
./drivers/gpu/drm/nouveau/nouveau_platform.c: func = of_device_get_match_data(&pdev->dev);
./drivers/gpu/drm/exynos/exynos_drm_rotator.c: of_device_get_match_data(dev);
./drivers/gpu/drm/exynos/exynos_mixer.c: drv = of_device_get_match_data(dev);
./drivers/gpu/drm/exynos/exynos5433_drm_decon.c: ctx->out_type = (unsigned long)of_device_get_match_data(dev);
./drivers/gpu/drm/exynos/exynos_drm_fimd.c: ctx->driver_data = of_device_get_match_data(dev);
./drivers/gpu/drm/exynos/exynos_hdmi.c: hdata->drv_data = of_device_get_match_data(dev);
./drivers/gpu/drm/exynos/exynos_drm_dsi.c: dsi->driver_data = of_device_get_match_data(dev);
./drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c: dc_ops = (struct kirin_dc_ops *)of_device_get_match_data(dev);
./drivers/gpu/drm/msm/hdmi/hdmi_phy.c: phy->cfg = (struct hdmi_phy_cfg *)of_device_get_match_data(dev);
./drivers/gpu/drm/msm/hdmi/hdmi.c: of_device_get_match_data(dev);
./drivers/gpu/drm/msm/msm_drv.c: return (int) (unsigned long) of_device_get_match_data(dev);
./drivers/gpu/drm/rockchip/rockchip_drm_vop.c: vop_data = of_device_get_match_data(dev);
./sound/soc/sh/rcar/core.c: priv->flags = (unsigned long)of_device_get_match_data(dev);
./sound/soc/sh/rcar/rsrc-card.c: of_data = of_device_get_match_data(dev);
./sound/soc/sh/rcar/rsrc-card.c: const struct rsrc_card_of_data *of_data = of_device_get_match_data(dev);
anyone can give some useful information?
The canonical answer to your question can be found at LWN: Platform Devices and Device Trees. What you need is the proper guidance on using it. A Tutorial on the Device Tree is a reasonable instruction guide. For background, you should read about Linux and the Device Tree. Also, elinux.org has a few wikis that should help, like Device Tree Linux and Device Tree Usage and Device Tree Reference.
in the probe function of the driver there has to be/must be this line :
probe(struct bus_client *client,
const struct bus_device_id *id)
{
const struct of_device_id *match;
match = of_match_device(omap_gpio_match);
if (!match)
return -ENODEV;
else
//write the driver stuff for Probe
This is how the device tree is linked with your driver.
omap_gpio_match you have already linked with the "compatible id" which you have defined in the device tree and thats how driver has been linked with the device tree.
When you register your platform driver you initialize driver.bus with platform_bus_type callbacks:
int __platform_driver_register(struct platform_driver *drv, struct module *owner)
{
drv->driver.owner = owner;
drv->driver.bus = &platform_bus_type;
One of these callbacks is platform_match:
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match,
And this callback is used to bind driver to the device in device tree style if there is one:
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* When driver_override is set, only bind to the matching driver */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}

Difference between spi_driver.id_table and spi_driver.driver.of_match_table

I'm currently trying to understand how linux drivers work. As far as I know, A driver's probe/init function is called when the kernel parses the corresponding .compatible string in the device tree. However, in the arizona-spi driver it looks like there are multiple compatible strings referenced in different members:
static const struct spi_device_id arizona_spi_ids[] = {
{ "wm5102", WM5102 },
{ "wm5110", WM5110 },
{ },
};
MODULE_DEVICE_TABLE(spi, arizona_spi_ids);
static struct spi_driver arizona_spi_driver = {
.driver = {
.name = "arizona",
.owner = THIS_MODULE,
.pm = &arizona_pm_ops,
// Contains e.g. "wlf,wm5102"
.of_match_table = of_match_ptr(arizona_of_match),
},
.probe = arizona_spi_probe,
.remove = arizona_spi_remove,
.id_table = arizona_spi_ids, // Contains "wm5102" and "wm5110"
};
This is an excerpt from here.
So what is the difference between arizona_spi_driver.id_table and arizona_spi_driver.driver.of_match_table?
There are several mechanism for driver matching. The id_table is intended to be used for finding a match from stripped device-tree entries (without vendor part), while of_match_table is used to find a match from full device-tree entries (the ones with vendor part).
If you check, arizona_of_match is defined as this:
const struct of_device_id arizona_of_match[] = {
{ .compatible = "wlf,wm5102", .data = (void *)WM5102 },
{ .compatible = "wlf,wm5110", .data = (void *)WM5110 },
{ .compatible = "wlf,wm8280", .data = (void *)WM8280 },
{ .compatible = "wlf,wm8997", .data = (void *)WM8997 },
{},
};
wlf is the vendor part for this case, while arizona_spi_ids doesn't contain the vendor part.
Hence, if you have something like this in your device tree:
compatible = "myvendor,wm5102"
Your device will match against id_table but not against of_match_table since the vendor is different.
The kernel will do matching against of_match_table first before check id_table (see spi_get_device_id in here). The device matching priority is: of_match_table > acpi_driver > id_table.

Linux kernel driver same device on different buses?

Is there an example of same device using different buses, for example spi and i2c (simultaneously, depending on the choice)?
I am interested in a device that have some common routines, but uses different read/write functions.
For example an adc that has common function for calibration or triggering (never seen this in kernel adc drivers, but why not?), but different functions to read samples from different sources.
How such driver can be realized?
Should i do something like this in my module? :
static struct i2c_driver my_i2c_driver = {
.driver = {
.name = "my-i2c-driver",
},
.probe = my_i2c_driver_probe,
.remove = my_i2c_driver_remove,
};
static struct spi_driver my_spi_driver = {
.driver = {
.name = "my-spi-driver",
},
.probe = my_spi_driver_probe,
.remove = my_spi_driver_remove,
};
etc... for read/write, ops
I'm interested in theory, even if the "no need", "no one does that."
Actually in 3.10.25 kernel there is such an example,
A ST magnetometer LIS3MDL wich has indeed two interface i2c/spi, controlled via gpio input.
With drivers included in kernel official tree, located in drivers/iio/magnetometer.
With 2 separate driver modules located in st_magn_i2c.c and st_magn_spi.c
st_magn_i2c.c:
static struct spi_driver st_magn_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "st-magn-spi",
},
.probe = st_magn_spi_probe,
.remove = st_magn_spi_remove,
.id_table = st_magn_id_table,
};
st_magn_spi.c:
static struct i2c_driver st_magn_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "st-magn-i2c",
},
.probe = st_magn_i2c_probe,
.remove = st_magn_i2c_remove,
.id_table = st_magn_id_table,
};
Such devices some times happens - for example PCA2129T RTC.
So in assume this is an example i was almost looking for, though i wanted something more trickier (like a USB and something else) or some basic lead.

How to change LED trigger?

I have register in BSP's the LED:
static struct gpio_led ic_leds[] = {
{
.name = "led1:green",
.gpio = USER_LED,
.default_trigger = "heartbeat",
.active_low = 1,
},
};
static struct gpio_led_platform_data ic_led_info = {
.num_leds = ARRAY_SIZE(ic_leds),
.leds = ic_leds,
};
static struct platform_device ic_leds_device = {
.name = "leds-gpio",
.id = -1,
.dev = {
.platform_data = &ic_led_info,
},
};
static void __init ic_add_device_leds(void)
{
platform_device_register(&ic_leds_device);
}
How can I change the trigger in run time? I know that it's possible with sysfs, but maybe exist another way?
echo "thetriggeryouwant" > /sys/class/leds/someled/trigger
where thetriggeryouwant is for example phy0rx and someled is the name of the led you want to change the trigger for.
To get all available triggers for that led, you can cat the file:
cat /sys/class/leds/someled/trigger
gives for example:
[none] timer oneshot mtd nand-disk heartbeat backlight gpio cpu cpu0 cpu1 activity default-on 2188000.ethernet-2:00:link 2188000.ethernet-2:00:100Mbps 2188000.ethernet-2:00:10Mbps
where the item in brackets ([none]) denotes the current trigger.

Resources