Linux内核4.14版本——SPI框架(5)——spi device相关

本文详细介绍了Linux SPI设备驱动中 spi_add_device 和 spi_setup 函数的实现过程。 spi_add_device 首先验证chip_select,设置bus ID字符串,然后分配cs_gpio,并调用spi_setup进行模式检查和初始化。spi_setup中,主要检查DUAL和QUAD模式不能同时设置,SPI_3WIRE模式下禁用DUAL和QUAD,设置默认bits_per_word和max_speed_hz,并调用控制器的setup方法。这些步骤确保了SPI设备正确且有效地添加到系统中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1. spi_add_device

1.1 spi_dev_set_name(设置bus id)

1.2 spi_setup(参数的一些默认设置和检查)

2. spi_alloc_device


1. spi_add_device

int spi_add_device(struct spi_device *spi)
{
	.....
	/* Chipselects are numbered 0..max; validate. */
	if (spi->chip_select >= ctlr->num_chipselect) {
		dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
			ctlr->num_chipselect);
		return -EINVAL;
	}

	/* Set the bus ID string */
	spi_dev_set_name(spi);
	
	.......
	
	if (ctlr->cs_gpios)
		spi->cs_gpio = ctlr->cs_gpios[spi->chip_select];

	/* Drivers may modify this initial i/o setup, but will
	 * normally rely on the device being setup.  Devices
	 * using SPI_CS_HIGH can't coexist well otherwise...
	 */
	status = spi_setup(spi);
	......
	/* Device may be bound to an active driver when this returns */
	status = device_add(&spi->dev);
	......
}

1.1 spi_dev_set_name(设置bus id)

static void spi_dev_set_name(struct spi_device *spi)
{
	struct acpi_device *adev = ACPI_COMPANION(&spi->dev);

	if (adev) {
		dev_set_name(&spi->dev, "spi-%s", acpi_dev_name(adev));
		return;
	}

	dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->controller->dev),
		     spi->chip_select);
}

1.2 spi_setup(参数的一些默认设置和检查)

int spi_setup(struct spi_device *spi)
{
	unsigned	bad_bits, ugly_bits;
	int		status;

	/* check mode to prevent that DUAL and QUAD set at the same time
	 */
	if (((spi->mode & SPI_TX_DUAL) && (spi->mode & SPI_TX_QUAD)) ||
		((spi->mode & SPI_RX_DUAL) && (spi->mode & SPI_RX_QUAD))) {
		dev_err(&spi->dev,
		"setup: can not select dual and quad at the same time\n");
		return -EINVAL;
	}
	/* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden
	 */
	if ((spi->mode & SPI_3WIRE) && (spi->mode &
		(SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)))
		return -EINVAL;
	/* help drivers fail *cleanly* when they need options
	 * that aren't supported with their current controller
	 */
	bad_bits = spi->mode & ~spi->controller->mode_bits;
	ugly_bits = bad_bits &
		    (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD);
	if (ugly_bits) {
		dev_warn(&spi->dev,
			 "setup: ignoring unsupported mode bits %x\n",
			 ugly_bits);
		spi->mode &= ~ugly_bits;
		bad_bits &= ~ugly_bits;
	}
	if (bad_bits) {
		dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
			bad_bits);
		return -EINVAL;
	}

	if (!spi->bits_per_word)
		spi->bits_per_word = 8;

	status = __spi_validate_bits_per_word(spi->controller,
					      spi->bits_per_word);
	if (status)
		return status;

	if (!spi->max_speed_hz)
		spi->max_speed_hz = spi->controller->max_speed_hz;

	if (spi->controller->setup)
		status = spi->controller->setup(spi);

	spi_set_cs(spi, false);

	dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n",
			(int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
			(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
			(spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
			(spi->mode & SPI_3WIRE) ? "3wire, " : "",
			(spi->mode & SPI_LOOP) ? "loopback, " : "",
			spi->bits_per_word, spi->max_speed_hz,
			status);

	return status;
}

(1)检查DUAL and QUAD是否同时存在

(2)如果是SPI_3WIRE,则禁止DUAL and QUAD

(3)如果spi->bits_per_word为0,默认设置为spi->bits_per_word = 8。

(4)设置默认的max_speed_hz

(5)调用spi->controller->setup

(6)片选选为非工作模式

2. spi_alloc_device

struct spi_device *spi_alloc_device(struct spi_controller *ctlr)
{
	struct spi_device	*spi;

	if (!spi_controller_get(ctlr))
		return NULL;

	spi = kzalloc(sizeof(*spi), GFP_KERNEL);
	if (!spi) {
		spi_controller_put(ctlr);
		return NULL;
	}

	spi->master = spi->controller = ctlr;
	spi->dev.parent = &ctlr->dev;
	spi->dev.bus = &spi_bus_type;
	spi->dev.release = spidev_release;
	spi->cs_gpio = -ENOENT;

	spin_lock_init(&spi->statistics.lock);

	device_initialize(&spi->dev);
	return spi;
}

<think>嗯,用户问的是初级Linux驱动开发工程师的简历怎么写。首先,我需要考虑用户可能的情况。他可能是一个刚毕业的学生,或者刚转行到Linux驱动开发领域,缺乏实际工作经验。这时候,他需要一份能够突出自己技能和项目经验的简历,即使没有太多工作经历,也要让招聘方看到他的潜力和基础知识。 用户的需求很明确,但可能还有一些隐藏的需求。比如,他可能担心自己没有相关的工作经验,不知道如何展示自己的能力。这时候,我应该建议他通过教育背景、个人项目、实习经历或者开源贡献来弥补工作经验的不足。另外,他可能不太清楚驱动开发的具体技能点需要哪些,需要详细列出相关技术栈,比如内核模块、设备树、驱动程序框架等。 接下来,我要考虑简历的结构。通常包括个人信息、求职意向、技术技能、项目经验、教育背景、证书与奖项、自我评价和附加信息。每个部分需要具体化,尤其是技术技能部分,要分门别类,让招聘方一目了然。 在技术技能方面,要确保涵盖Linux内核、驱动开发框架、硬件接口、调试工具、编程语言、本控制和软技能。对于初级工程师来说,可能对某些高级技术不太熟悉,但要诚实,同时突出自己的学习能力和项目中的应用。 项目经验是关键部分。用户可能没有正式的工作经验,但可能有课程项目、毕业设计或开源贡献。需要指导他如何描述这些项目,使用STAR法则,量化成果,比如优化了启动速度,减少了内存占用等。 教育背景要突出相关课程,比如操作系统、计算机组成原理等,如果有高绩点或者奖学金,也可以强调。证书方面,像CompTIA Linux+、LPI认证是不错的选择,但用户可能还没有,可以建议考取或列入学习计划。 自我评价要避免空洞,结合实例,比如“独立完成字符设备驱动开发”这样的具体描述。附加信息如GitHub链接、技术博客,可以展示他的实际代码和技术思考,这对初级工程师来说很重要。 最后,注意事项部分要提醒用户避免夸大,根据岗位调整简历,检查拼写错误。这些细节往往容易被忽视,但很重要。 总结下来,用户需要一个结构清晰、重点突出、真实可信的简历框架,帮助他在竞争激烈的求职中展示自己的优势和潜力,即使经验不足,也能通过项目和技能打动招聘方。</think>以下是为初级Linux驱动开发工程师量身定制的简历编写指南,采用技术文档风格的结构化表述: --- ### 一、简历结构框架 ``` [个人信息] 姓名 | 联系方式 | 邮箱 | GitHub/技术博客(可选) (注:建议使用专业邮箱如Gmail,避免使用QQ邮箱) [求职意向] Linux驱动开发工程师(初级) | 嵌入式系统开发方向 [技术技能](核心展示区) 1. Linux内核 - 熟悉内核模块开发流程(Makefile/Kconfig) - 掌握字符设备/块设备驱动框架 - 了解设备树(Device Tree)配置与解析 2. 硬件接口 - 调试过I2C/SPI/UART等总线协议 - 实操GPIO中断/PWM控制 - 熟悉MMU内存管理机制 3. 开发工具链 - 使用GCC交叉编译工具链 - 掌握gdb/kgdb调试技术 - 熟练使用Git本控制 [项目经验](关键内容) 1. [ARM平台GPIO驱动开发](示例项目) - 基于Linux 4.19内核实现LED控制模块 - 编写字符设备驱动文件(led_driver.c) - 使用udev规则实现设备节点自动创建 - 成果:成功通过sysfs接口控制开发板LED状态 2. [虚拟字符设备开发] - 实现open/release/read/write等文件操作接口 - 添加ioctl命令实现状态控制 - 使用内核定时器实现数据模拟 - 性能:用户态读写速度达到120MB/s [教育背景] [年份] - [年份] [学校名称] 计算机科学与技术 本科 - 主修课程:操作系统原理、计算机组成原理、C语言程序设计 - 毕业设计:基于Linux的温湿度传感器驱动开发(如适用) [证书与奖项] - CompTIA Linux+(如有) - 全国大学生电子设计竞赛三等奖(示例) [自我评价] - 熟悉Linux内核开发流程,具备独立完成简单驱动模块开发能力 - 理解VFS、中断处理、DMA等内核机制 - 持续关注内核邮件列表(LKML)更新动态 ``` --- ### 二、技术要点强化建议 1. **驱动开发术语规范** - 使用准确技术表述: $$ \text{正确:实现platform\_driver\_register()注册流程} $$ $$ \text{避免:做了驱动注册相关的工作} $$ 2. **项目描述方法论** - 采用STAR法则: ``` Situation:开发板型号(如i.MX6UL) Task:需要实现USB OTG功能支持 Action:修改dts配置,编写EHCI驱动补丁 Result:成功识别U盘设备,传输速率达480Mbps ``` 3. **量化指标呈现** - 中断延迟优化:从15ms降低至2ms - 内存占用:驱动模块体积缩减至32KB - 兼容性:支持kernel 4.14~5.10本 --- ### 三、避坑指南 1. **技术表述禁忌** - 错误示例:"精通Linux内核开发" - 建议表述:"熟悉Linux内核子系统工作机制" 2. **真实性保障** - 避免虚构未掌握的技能(如PCIe驱动开发) - 可注明技术掌握程度: $$ \text{掌握程度梯度:了解→熟悉→精通} $$ 3. **硬件平台标注** - 明确标注开发平台: ``` 树莓派4B | BeagleBone Black | Xilinx Zynq-7000 ``` --- ### 四、进阶建议 1. **开源贡献标注** - 若参与过内核补丁提交: ``` 向LKML提交了GPIO驱动改进补丁(补丁ID:123456) ``` 2. **调试经验展示** - 内核oops分析案例 - printk调试技巧 - SystemTap使用经验 3. **持续学习证明** - 跟进内核本特性(如6.x本新特性) - 参与本地Linux用户组活动 --- > 注:建议将简历控制在一页A4纸,重点突出驱动开发相关技能。可附加技术博客链接(如对ioctl实现原理的分析文章)作为能力佐证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值