supporting multi function devices in the linux kernel a
play

Supporting multi-function devices in the Linux kernel: a tour of the - PowerPoint PPT Presentation

Embedded Linux Conference Europe 2015 Supporting multi-function devices in the Linux kernel: a tour of the mfd, regmap and syscon APIs Alexandre Belloni alexandre.belloni@free-electrons.com http://free-electrons.com 1/30 free electrons free


  1. Embedded Linux Conference Europe 2015 Supporting multi-function devices in the Linux kernel: a tour of the mfd, regmap and syscon APIs Alexandre Belloni alexandre.belloni@free-electrons.com http://free-electrons.com 1/30 free electrons free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  2. Alexandre Belloni subsystem http://free-electrons.com ARM (Berlin) processors ARM processors 2/30 ▶ Embedded Linux engineer at free electrons ▶ Embedded Linux expertise ▶ Development , consulting and training ▶ Strong open-source focus ▶ Open-source contributor ▶ Maintainer for the Linux kernel RTC ▶ Co-Maintainer of kernel support for Atmel free electrons ▶ Contributing to kernel support for Marvell Embedded Linux Experts free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  3. What is a multi-function device ? USB interface controller http://free-electrons.com specialized i2c_client or spi_device ) external peripherals are represented by only one struct device (or the backlight controller, status LED controller, GPIOs, ON key, ADC driver, ON key functionality 3/30 ▶ An external peripheral or a hardware block exposing more than a single ▶ Examples: ▶ PMICs ▶ da9063: regulators, led controller, watchdog, rtc, temperature sensor, vibration motor ▶ max77843: regulators, charger, fuel gauge, haptic feedback, LED controller, micro ▶ wm831x: regulator, clocks, rtc, watchdog, touch controller, temperature sensor, ▶ some even include a codec ▶ atmel-hlcdc: display controller and backlight pwm ▶ Diolan DLN2: USB to I2C, SPI and GPIO controllers ▶ Realtek PCI-E card reader: SD/MMC and memory stick reader ▶ The main issue is to register those in difgerent kernel subsystems. In particular the free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  4. MFD subsystem and handle IRQs subsystems. http://free-electrons.com 4/30 ▶ The MFD subsystem has been created to handle those devices ▶ Allows to register the same device in multiple subsystems ▶ The MFD driver has to multiplex access on the bus (mainly takes care of locking) ▶ May handle clocks ▶ May also need to confjgure the IP ▶ May do variant or functions detection ▶ Other benefjt: allows driver reuse, multiple MFD can reuse drivers from other free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  5. MFD API const struct mfd_cell *cells, int n_devs, struct resource *mem_base, int irq_base, struct irq_domain *irq_domain); mfd_cell_disable but they are seldom used. http://free-electrons.com 5/30 ▶ Defjned in include/linux/mfd/core.h ▶ Implemented in drivers/mfd/mfd-core.c ▶ int mfd_add_devices(struct device *parent, int id, ▶ extern void mfd_remove_devices(struct device *parent); ▶ Also mfd_add_hotplug_devices , mfd_clone_cell , mfd_cell_enable , free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  6. struct mfd_cell struct mfd_cell { http://free-electrons.com }; [...] *resources; const struct resource num_resources; int */ * For accessing hardware you should use resources from the platform dev * These resources can be specified relative to the parent device. /* [...] *of_compatible; const char */ * See: Documentation/devicetree/usage-model.txt Chapter 2.2 for details * Device Tree compatible string /* pdata_size; size_t *platform_data; void /* platform data passed to the sub devices drivers */ [...] id; int *name; const char 6/30 free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  7. Example: tps6507x - registration subsys_initcall(tps6507x_i2c_init); }; static int __init tps6507x_i2c_init(void) { return i2c_add_driver(&tps6507x_i2c_driver); } /* init early so consumer devices can complete system boot */ static void __exit tps6507x_i2c_exit(void) static const struct i2c_device_id tps6507x_i2c_id[] = { { i2c_del_driver(&tps6507x_i2c_driver); } module_exit(tps6507x_i2c_exit); initcall(tps6507x_i2c_init); to register early enough http://free-electrons.com .id_table = tps6507x_i2c_id, .remove = tps6507x_i2c_remove, .probe = tps6507x_i2c_probe, {}, { } }; MODULE_DEVICE_TABLE(i2c, tps6507x_i2c_id); #ifdef CONFIG_OF static const struct of_device_id tps6507x_of_match[] = { }, 7/30 }; MODULE_DEVICE_TABLE(of, tps6507x_of_match); #endif static struct i2c_driver tps6507x_i2c_driver = { .driver = { .of_match_table = of_match_ptr(tps6507x_of_match), { "tps6507x", 0 }, {.compatible = "ti,tps6507x", }, ▶ registers as a simple i2c device .name = "tps6507x", ▶ only oddity subsys_ free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  8. Example: tps6507x - probing { http://free-electrons.com } return mfd_add_devices(tps6507x->dev, -1, tps6507x_devs, tps6507x->write_dev = tps6507x_i2c_write_device; tps6507x->read_dev = tps6507x_i2c_read_device; tps6507x->i2c_client = i2c; tps6507x->dev = &i2c->dev; i2c_set_clientdata(i2c, tps6507x); return -ENOMEM; if (tps6507x == NULL) GFP_KERNEL); static const struct mfd_cell tps6507x_devs[] = { struct tps6507x_dev *tps6507x; const struct i2c_device_id *id) }; { }, { static int tps6507x_i2c_probe(struct i2c_client *i2c, }, drivers/regulator/tps6507x-regulator.c drivers/input/touchscreen/tps6507x-ts.c 8/30 ▶ tps6507x-pmic in .name = "tps6507x-pmic", ▶ tps6507x-ts in .name = "tps6507x-ts", tps6507x = devm_kzalloc(&i2c->dev, sizeof(struct tps6507x_dev), ARRAY_SIZE(tps6507x_devs), NULL, 0, NULL); free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  9. Example: tps6507x - struct tps6507x_dev void *src); http://free-electrons.com drivers. }; struct tps6507x_dev { [...] int (*write_dev)(struct tps6507x_dev *tps6507x, char reg, int size, void *dest); int (*read_dev)(struct tps6507x_dev *tps6507x, char reg, int size, struct i2c_client *i2c_client; struct device *dev; 9/30 ▶ Defjned in include/linux/mfd/tps6507x.h ▶ Allows to pass the i2c_client and the accessors. ▶ tps6507x.h also contains the register defjnitions that can be used in the function free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  10. Example: tps6507x - function drivers static int tps6507x_ts_probe(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); [...] }; static int tps6507x_pmic_probe(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); [...] }; http://free-electrons.com 10/30 ▶ Easy to get the struct tps6507x_dev by using dev.parent free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  11. Example: da9063 - registering [...] .name = DA9063_DRVNAME_RTC, .num_resources = ARRAY_SIZE(da9063_rtc_resources), .resources = da9063_rtc_resources, .of_compatible }, }; [...] like it was done using platform_data named for easy retrieval .of_compatible , the function has to be a child of the MFD (see bindings) http://free-electrons.com static struct resource da9063_rtc_resources[] = { { static const struct mfd_cell da9063_devs[] = { }, { .name .start = DA9063_IRQ_ALARM, .end = DA9063_IRQ_ALARM, .flags = IORESOURCE_IRQ, }; 11/30 { .name .start = DA9063_IRQ_TICK, .end = DA9063_IRQ_TICK, .flags = IORESOURCE_IRQ, } = "ALARM", ▶ resources are defjned = "TICK", ▶ in that case, they are ▶ when using = "dlg,da9063-rtc", free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  12. Example: da9063 - drivers/rtc/rtc-da9063.c static int da9063_rtc_probe(struct platform_device *pdev) http://free-electrons.com standalone chip. platform_get_irq , platform_get_irq_byname to retrieve the resources }; [...] } return ret; irq_alarm, ret); if (ret) { "ALARM", rtc); IRQF_TRIGGER_LOW | IRQF_ONESHOT, da9063_alarm_event, [...] { 12/30 irq_alarm = platform_get_irq_byname(pdev, "ALARM"); ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL, dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", ▶ Use platform_get_resource , platform_get_resource_byname , ▶ Doesn’t even need dev.parent , the same driver could be used for an MFD and a free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  13. Example: da9063 - DT bindings pmic0: da9063@58 { reg = <0x58>; interrupt-parent = <&gpio6>; interrupts = <11 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; rtc { }; [...] }; http://free-electrons.com 13/30 compatible = "dlg,da9063" compatible = "dlg,da9063-rtc"; free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

  14. MFD: multiplexing register access register sets is to use regmap . pass it down to the children http://free-electrons.com 14/30 ▶ A common way of multiplexing access to ▶ Create the regmap from the MFD driver and free electrons - Embedded Linux, kernel, drivers and Android - Development, consulting, training and support.

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend