Analysis of kernel version 5.1.3
1.MFD full name
Multi-function Device, multifunction device
2. Why will MFD subsystem
Since the emergence of a class of the peripheral device having multiple functions within or integrated hardware module cpu
3. What multifunction devices have it?
3.1 PMIC, the power management chip
da9063: regulator, led controller, watchdog controller real-time clock, a temperature sensor, a vibration motor driving, long press shutdown (ON key)
max77843: regulator, charger, fuel gauge, tactile feedback, led controllers, micro USB interface controller
wm831x: regulator, a clock, real time clock control, watchdog, the touch controller, a temperature sensor, a backlight controller, a state led controller, GPIO, long press shutdown (ON key), ADC
Other: even with the codec function
3.2 atmel-hlcdc: the backlight and the display controller pwm
3.3 Diolan DLN2: USB transfer I2C, SPI, and GPIO controller
3.4 Realtek PCI-E Card Reader: SD / MMC and Memory Stick reader
The main problem 4. MFD subsystem solutions of
These drivers are registered in different kernel subsystems. In particular external peripheral device is only rendered by a structure struct device (or designated i2c_client or spi_device)
5. MFD subsystem advantage of what?
5.1 is allowed to register the same device in the plurality of subsystems
5.2 MFD drive can be multiplexed bus (mainly processed on the lock) and interrupt request
5.3 processing clock
5.4 you need to configure IP
5.5 allows the drive to reuse, a plurality of multi-function device driver can be reused in other subsystems
6. MFD provides API
int mfd_add_devices(struct device *parent,int id, const struct mfd_cell *cells, int n_devs,
struct resource *mem_base, int irq_base, struct irq_domain *irq_domain);
extern void mfd_remove_devices(struct device *parent);
These interfaces are defined in the include / linux / mfd / core.h of, be implemented within drivers / mfd / mtd-core.c in
7. The structure of the MFD provided
struct mfd_cell { const char *name; int id; /* refcounting for multiple drivers to use a single cell */ atomic_t *usage_count; int (*enable)(struct platform_device *dev); int (*disable)(struct platform_device *dev); int (*suspend)(struct platform_device *dev); int (*resume)(struct platform_device *dev); /* platform data passed to the sub devices drivers */ void *platform_data; size_t pdata_size; /* device properties passed to the sub devices drivers */ struct property_entry *properties; /* * Device Tree compatible string * See: Documentation/devicetree/usage-model.txt Chapter 2.2 for details */ const char *of_compatible; /* Matches ACPI */ const struct mfd_cell_acpi_match *acpi_match; /* * These resources can be specified relative to the parent device. * For accessing hardware you should use resources from the platform dev */ int num_resources; const struct resource *resources; /* don't check for resource conflicts */ bool ignore_resource_conflicts; /* * Disable runtime PM callbacks for this subdevice - see * pm_runtime_no_callbacks(). */ bool pm_runtime_no_callbacks; /* A list of regulator supplies that should be mapped to the MFD * device rather than the child device when requested */ const char * const *parent_supplies; int num_parent_supplies; };
Example 8. Analysis
8.1 Analysis of multi-function drive tps6507x
8.1.1 documents involved
drivers/mfd/tps6507x.c
include/linux/mfd/tps6507x.h
drivers/regulator/tps6507x-regulator.c
drivers/input/touchscreen/tps6507x-ts.c
8.1.2 according to the structure
static const struct mfd_cell tps6507x_devs[] = { { .name = "tps6507x-pmic", }, { .name = "tps6507x-ts", }, };
Can be derived from the above structure, tps6507x series chip serves two functions: power management features (regulator) + touch screen function (Touchscreen)
static struct i2c_driver tps6507x_i2c_driver = { .driver = { .name = "tps6507x", .of_match_table = of_match_ptr(tps6507x_of_match), }, .probe = tps6507x_i2c_probe, .id_table = tps6507x_i2c_id, };
This structure provides a probe function is tps6507x tps6507x_i2c_probe
struct tps6507x_dev { struct device *dev; struct i2c_client *i2c_client; int (*read_dev)(struct tps6507x_dev *tps6507x, char reg, int size, void *dest); int (*write_dev)(struct tps6507x_dev *tps6507x, char reg, int size, void *src); /* Client devices */ struct tps6507x_pmic *pmic; };
tps6507x of read-write interface is placed in this structure, which is the so-called common
8.1.3 tps6507x initialize
subsys_initcall(tps6507x_i2c_init);
Call path as follows:
tps6507x_i2c_init->i2c_add_driver
8.1.4 Probe functions tps6507x_i2c_probe done?
Register read and write functions of tps6507x: tps6507x_i2c_read_device tps6507x_i2c_write_device and to the structure struct tps6507x_dev
Two functions 8.1.5 tps6507x implementation where is it?
drivers / regulator / tps6507x-regulator.c, which are to achieve power management functions (drive voltage regulator)
drivers / input / touchscreen / tps6507x-ts.c, which are to achieve the touch screen function
8.1.6 tps6507x driving voltage regulator
8.1.6.1 call path
subsys_initcall(tps6507x_pmic_init);
tps6507x_pmic_init->platform_driver_register
8.1.6.2 probe function tps6507x_pmic_probe what did?
Obtaining a common structure struct tps6507x_dev
Re-register the associated structure in order to provide a user interface pmic follows:
static struct regulator_ops tps6507x_pmic_ops = { .is_enabled = pmic function tps6507x_pmic_is_enabled, check whether the tps6507x enabled .enable = tps6507x_pmic_enable, so that the function can tps6507x pmic of .disable = tps6507x_pmic_disable, tsp6507x disable the function pmic .get_voltage_sel = tps6507x_pmic_get_voltage_sel, acquires the voltage value .set_voltage_sel = tps6507x_pmic_set_voltage_sel, set voltage value .list_voltage = regulator_list_voltage_table, listed voltmeter .map_voltage = regulator_map_voltage_ascend, };
8.1.7 tps6507x touch screen driver
8.1.7.1 drive Where?
drivers/input/touchscreen/tps6507x-ts.c
8.1.7.2 Analysis probe functions are done?
Obtaining common structure struct tps6507x_dev
Filling structure struct tps6507x_ts, the key is registered as a function tps6507x_ts_poll
References: