首页 > 系统相关 >01-[Linux][MFD]MFD模块介绍

01-[Linux][MFD]MFD模块介绍

时间:2023-08-10 15:59:37浏览次数:47  
标签:01 MFD struct dev tps6507x init tps Linux data

1、MFD功能介绍

MFD(Multi-function Device)多功能设备,许多有共性的设备的集合,MFD由核心层(core)以及其下的“子设备”组成。从下文将会看到,MFD只是将设备注册到platform总线--因此,其子设备属于platform设备。它并没有对涉及到的设备或者驱动做实质性改变。但是,因为某些设备的共性,所以可以在MFD中提供共同的函数给其下子设备进行调用。

2、为什么会出现MFD子系统,以及有哪些多功能设备?

由于出现了一类具有多种功能的外围或CPU内部集成的硬件模块。
多功能设备有:

  • PMIC,电源管理芯片
  • DA9063:调节器,LED控制器,看门狗,实时时钟控制器,温度传感器,震动马达驱动,长按关机功能(ON key)
  • MAX77843:调节器,充电器,燃油量表,触觉反馈,LED控制器,micro USB接口控制器
  • Diolan DLN2:USB转i2c,SPI和GPIO控制器

3、MFD子系统的优点

  • 允许在多个子系统中注册相同的驱动
  • 允许驱动重用,多个多功能设备能重用其它子系统中的驱动

4、MFD提供的API

以下接口定义在include/linux/mfd/core.h中,在drivers/mfd/mfd-core.c中被实现:

extern 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);

5、tps6507x器件案例分析

5.1 tps6507x器件的驱动代码相关的路径如下:

include/linux/mfd/tps6507x.h
include/linux/input/tps6507x-ts.h

drivers/mfd/tps6507x.c
drivers/regulator/tps6507x-regulator.c
drivers/input/touchscreen/tps6507x-ts.c

5.2 tps6507x结构体

  • 从该结构体可以看出,tps6507x系列芯片提供两种功能:电源管理功能(regulator)+触摸屏功能(touchscreen)
static const struct mfd_cell tps6507x_devs[] = {
	{
		.name = "tps6507x-pmic",
	},
	{
		.name = "tps6507x-ts",
	},
};
  • tps6507x的读写接口是放在以下的结构体中,也就是所谓的共性
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;
};

5.3 驱动代码分析

  • tps6507x.c驱动文件分析
    subsys_initcall(tps6507x_i2c_init) => i2c_add_driver(&tps6507x_i2c_driver) => tps6507x_i2c_probe
static int tps6507x_i2c_probe(struct i2c_client *i2c,
			    const struct i2c_device_id *id)
{
	struct tps6507x_dev *tps6507x;

	tps6507x = devm_kzalloc(&i2c->dev, sizeof(struct tps6507x_dev),
				GFP_KERNEL);
	if (tps6507x == NULL)
		return -ENOMEM;

	// 该函数调用dev_set_drvdata()函数绑定tps6507x结构体
	i2c_set_clientdata(i2c, tps6507x);
	tps6507x->dev = &i2c->dev;
	tps6507x->i2c_client = i2c;
	// 初始化读写函数
	tps6507x->read_dev = tps6507x_i2c_read_device;
	tps6507x->write_dev = tps6507x_i2c_write_device;

	return devm_mfd_add_devices(tps6507x->dev, -1, tps6507x_devs,
				    ARRAY_SIZE(tps6507x_devs), NULL, 0, NULL);
}
  • tps6507x的电压调节器驱动(tps6507x-regulator.c)
    subsys_initcall(tps6507x_pmic_init) => platform_driver_register(&tps6507x_pmic_driver) => tps6507x_pmic_probe
static int tps6507x_pmic_probe(struct platform_device *pdev)
{
	// 获取在mfd中通过i2c_set_clientdata设置的数据
	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
	struct tps_info *info = &tps6507x_pmic_regs[0];
	struct regulator_config config = { };
	struct regulator_init_data *init_data;
	struct regulator_dev *rdev;
	struct tps6507x_pmic *tps;
	struct tps6507x_board *tps_board;
	struct of_regulator_match *tps6507x_reg_matches = NULL;
	int i;
	int error;
	unsigned int prop;

	/**
	 * tps_board points to pmic related constants
	 * coming from the board-evm file.
	 */

	tps_board = dev_get_platdata(tps6507x_dev->dev);
	if (IS_ENABLED(CONFIG_OF) && !tps_board &&
		tps6507x_dev->dev->of_node)
		tps_board = tps6507x_parse_dt_reg_data(pdev,
				&tps6507x_reg_matches);
	if (!tps_board)
		return -EINVAL;

	/**
	 * init_data points to array of regulator_init structures
	 * coming from the board-evm file.
	 */
	init_data = tps_board->tps6507x_pmic_init_data;
	if (!init_data)
		return -EINVAL;

	tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL);
	if (!tps)
		return -ENOMEM;

	mutex_init(&tps->io_lock);

	/* common for all regulators */
	tps->mfd = tps6507x_dev;

	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
		/* Register the regulators */
		tps->info[i] = info;
		if (init_data->driver_data) {
			struct tps6507x_reg_platform_data *data =
					init_data->driver_data;
			tps->info[i]->defdcdc_default = data->defdcdc_default;
		}

		tps->desc[i].name = info->name;
		tps->desc[i].id = i;
		tps->desc[i].n_voltages = info->table_len;
		tps->desc[i].volt_table = info->table;
		// 设置regulator的操作函数
		tps->desc[i].ops = &tps6507x_pmic_ops;
		tps->desc[i].type = REGULATOR_VOLTAGE;
		tps->desc[i].owner = THIS_MODULE;

		config.dev = tps6507x_dev->dev;
		config.init_data = init_data;
		config.driver_data = tps;

		if (tps6507x_reg_matches) {
			error = of_property_read_u32(
				tps6507x_reg_matches[i].of_node,
					"ti,defdcdc_default", &prop);

			if (!error)
				tps->info[i]->defdcdc_default = prop;

			config.of_node = tps6507x_reg_matches[i].of_node;
		}

		rdev = devm_regulator_register(&pdev->dev, &tps->desc[i],
					       &config);
		if (IS_ERR(rdev)) {
			dev_err(tps6507x_dev->dev,
				"failed to register %s regulator\n",
				pdev->name);
			return PTR_ERR(rdev);
		}

		/* Save regulator for cleanup */
		tps->rdev[i] = rdev;
	}

	tps6507x_dev->pmic = tps;
	// 该函数设置的数据不清楚在哪里被调用,在当前文件中没有调用platform_get_drvdata的地方
	platform_set_drvdata(pdev, tps6507x_dev);

	return 0;
}
// regulator的操作函数定义
static struct regulator_ops tps6507x_pmic_ops = {
	.is_enabled = tps6507x_pmic_is_enabled,
	.enable = tps6507x_pmic_enable,
	.disable = tps6507x_pmic_disable,
	.get_voltage_sel = tps6507x_pmic_get_voltage_sel,
	.set_voltage_sel = tps6507x_pmic_set_voltage_sel,
	.list_voltage = regulator_list_voltage_table,
	.map_voltage = regulator_map_voltage_ascend,
};
  • tps6507x触摸屏驱动(tps6507x-ts.c)
    获取MFD中使用i2c_set_clientdata绑定的tps6507x结构体;
    填充tps6507x_ts结构体,注册函数tps6507x_ts_poll函数。
static int tps6507x_ts_probe(struct platform_device *pdev)
{
	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
	const struct tps6507x_board *tps_board;
	const struct touchscreen_init_data *init_data;
	struct tps6507x_ts *tsc;
	struct input_polled_dev *poll_dev;
	struct input_dev *input_dev;
	int error;

	/*
	 * tps_board points to pmic related constants
	 * coming from the board-evm file.
	 */
	tps_board = dev_get_platdata(tps6507x_dev->dev);
	if (!tps_board) {
		dev_err(tps6507x_dev->dev,
			"Could not find tps6507x platform data\n");
		return -ENODEV;
	}

	/*
	 * init_data points to array of regulator_init structures
	 * coming from the board-evm file.
	 */
	init_data = tps_board->tps6507x_ts_init_data;

	tsc = devm_kzalloc(&pdev->dev, sizeof(struct tps6507x_ts), GFP_KERNEL);
	if (!tsc) {
		dev_err(tps6507x_dev->dev, "failed to allocate driver data\n");
		return -ENOMEM;
	}

	tsc->mfd = tps6507x_dev;
	tsc->dev = tps6507x_dev->dev;
	tsc->min_pressure = init_data ?
			init_data->min_pressure : TPS_DEFAULT_MIN_PRESSURE;

	snprintf(tsc->phys, sizeof(tsc->phys),
		 "%s/input0", dev_name(tsc->dev));

	poll_dev = devm_input_allocate_polled_device(&pdev->dev);
	if (!poll_dev) {
		dev_err(tsc->dev, "Failed to allocate polled input device.\n");
		return -ENOMEM;
	}

	tsc->poll_dev = poll_dev;

	poll_dev->private = tsc;
	poll_dev->poll = tps6507x_ts_poll;
	poll_dev->poll_interval = init_data ?
			init_data->poll_period : TSC_DEFAULT_POLL_PERIOD;

	input_dev = poll_dev->input;
	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);

	input_set_abs_params(input_dev, ABS_X, 0, MAX_10BIT, 0, 0);
	input_set_abs_params(input_dev, ABS_Y, 0, MAX_10BIT, 0, 0);
	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0);

	input_dev->name = "TPS6507x Touchscreen";
	input_dev->phys = tsc->phys;
	input_dev->dev.parent = tsc->dev;
	input_dev->id.bustype = BUS_I2C;
	if (init_data) {
		input_dev->id.vendor = init_data->vendor;
		input_dev->id.product = init_data->product;
		input_dev->id.version = init_data->version;
	}

	error = tps6507x_adc_standby(tsc);
	if (error)
		return error;

	// 注册poll设备,该函数需要研究下
	error = input_register_polled_device(poll_dev);
	if (error)
		return error;

	return 0;
}

参考文档

1、https://bootlin.com/pub/conferences/2015/elce/belloni-mfd-regmap-syscon/belloni-mfd-regmap-syscon.pdf
2、https://www.cnblogs.com/dakewei/p/10991941.html

标签:01,MFD,struct,dev,tps6507x,init,tps,Linux,data
From: https://www.cnblogs.com/hkcs596/p/17619697.html

相关文章

  • 嵌入式Linux ------ 一次简单的FrameBuffer驱动开发
    Linux一次简单的FrameBuffer驱动开发设施版本CPUAllwinnerF1C200slinux6.4.0-rc4显示器1.28inch16-grayscaleOLED128x128驱动ICSSD1327Orangepi5声明本驱动仓库位于:https://github.com/AllwinnerSuniv/suniv-epd/tree/main/ssd1327本驱动代......
  • linux连接Windows上的数据库
    /*定义一些数据库连接需要的宏*/#include<stdio.h>#include<string.h>#include<stdlib.h>/*引入连接Mysql的头文件*/#include<mysql/mysql.h>#defineHOST"Linux的IP地址"/*MySql服务器地址*/#defineUSERNAME"root"/*用户名*/#definePASSWORD&......
  • Linux下发现一个高安全性的系统管理工具
     软件AnySetup主要功能主要功能是对Linux操作系统下的基本配置进行管理、多种服务配置进行管理、安全配置进行管理等。如:操作系统的升级管理,软件包的安装、更新和卸载管理,软件仓库源的管理,系统时间和时区的管理,系统语言环境的管理,网络环境的配置管理,系统服务的启动、关闭、......
  • Audition Au 2017音频编辑软件下载和安装教程
    Audition是一款完善的工具集,其中包含用于创建、混合、编辑和复原音频内容的多轨、波形和光谱显示功能。这一强大的音频工作站旨在加快视频制作工作流程和音频修整的速度,并且还提供带有纯净声音的精美混音效果。软件介绍新机载体验为新用户提供了常见任务的一系列指导解决方法,例如......
  • Linux的MySQL数据库安装部署
    简介MySQL数据库,是知名的数据库系统,其特点是:轻量,简单,功能丰富。MySQL常用版本有MySQL5.7版本安装MySQL8.x版本安装MySQL在CentOS系统安装(5.7版本与8.0版本)注意:安装操作需要root权限安装配置yum仓库#导入更新密钥rpm--importhttps://repo.mysql.com/RPM-GPG......
  • Linux --- 修改控制台字体consolefont
    Linux---修改控制台字体consolefont用户层面对于debianlike的系统,可到如下路径查找consolefont$cd/usr/share/consolefonts/$lsArabic-Fixed15.psf.gzCyrSlav-VGA32x16.psf.gzFullGreek-VGA8.psf.gzLat15-VGA16.psf.gz......
  • 嵌入式 Linux ------ UBIFS 文件系统的使用
    LinuxUBIFS文件系统的使用平台环境如下设施版本CPUAllwinnerF1C100slinux6.4.0-rc4ubootv2023.07-rc4buildrootv2023.02闪存WinbondSPI-Nand128MBW25N01G从Buildroot生成UBIFS手动创建UBIFS参考如下内容3.制作ubifsUbifs的制作......
  • Linux开发板调用摄像头(V4L2编程,含YUYV解码RGB)
    本文是基于Linux开发板的V4L2摄像头调用程序,包括YUYV解码为RGB,以及将摄像头数据显示在开发板屏幕上。代码未封装,可直接在linux下编译使用。 工作流程:打开设备—>检查和设置设备属性—>设置帧格式—>设置一种输入输出方法(缓冲区管理)—>循环获取数据—>数据解码—>显......
  • UKIEPC 2017
    A-AlienSunset这到题,用一个数组表示当前时间有多少个星球是夜晚,这样就转换成了区间修改单点查询。因为只查询一次,所以用差分即可。#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintm=1825*100+5;int32_tmain(){ios::sync_wi......
  • 2018-03-28-markdown-total
    titlelayoutcategoriestagsexcerptMarkdown完整语法说明post编程markdown完整版markdown语法Markdown完整语法说明辛勤的搬运工,原文链接http://wowubuntu.com/markdown/index.html目录概述宗旨兼容HTML......