LinuxGod.net
Linux大神网——精选每一篇高品质的技术干货
  1. 首页
  2. 开源快讯
  3. 正文

一个/sys/bus/iio/devices:device0传感器

2022年12月5日 336点热度

Linux AP3216C驱动

AP3216C是一个近距离环境光传感器linux 驱动通知应用层linux 驱动通知应用层,包含了光强传感器(ALS:AmbientLight Sensor),接近传感器(PS: Proximity Sensor),还有一个红外LED(IR LED)。

1. 介绍

AP3216C是通过IIC进行操作的,操作地址为0x1Elinux操作系统,芯片有多种工作模式使用linux手机,详细的寄存器操作可以阅读芯片手册。我这里利用IIC子系统和IIO子系统进行开发,向应用层提供的sysfs接口。

2. 代码

// SPDX-License-Identifier: GPL-2.0-only
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define AP3216C_REGMAP_NAME	"ap3216c_regmap"
#define AP3216C_DRV_NAME	"ap3216c"
#define AP3216C_SYSTEMCONG	0x00	/* System Configuration */
#define AP3216C_INTSTATUS	0X01	/* Interrupt Status */
#define AP3216C_INTCLEAR	0X02	/* INT Clear Manner */
#define AP3216C_IRDATALOW	0x0A	/* IR Data Low */
#define AP3216C_IRDATAHIGH	0x0B	/* IR Data High */
#define AP3216C_ALSDATALOW	0x0C	/* ALS Data Low */
#define AP3216C_ALSDATAHIGH	0X0D	/* ALS Data High */
#define AP3216C_PSDATALOW	0X0E	/* PS Data Low */
#define AP3216C_PSDATAHIGH	0X0F	/* PS Data High */
#define AP3216C_ALSCONFIG	0X10	/* ALS Configuration */
#define AP3216C_PSCONFIG	0X20	/* PS Configuration */
#define AP3216C_PSLEDCONFIG 0X21	/* PS LED Driver */
enum ap3216c_idx {
	AP3216C_ALS,
	AP3216C_PS,
	AP3216C_IR,
};
struct ap3216c_data {
	struct i2c_client *client;
	struct iio_dev *indio_dev;
	struct mutex lock;
	struct regmap *regmap;
};
static const struct regmap_config ap3216c_regmap_config = {
	.name = AP3216C_REGMAP_NAME,
	.reg_bits = 8,
	.val_bits = 8,
};
static const unsigned long ap3216c_scan_masks[] = {
	BIT(AP3216C_ALS) | BIT(AP3216C_PS) | BIT(AP3216C_IR),
	0
};
static const struct iio_chan_spec ap3216c_channels[] = {
	/* ALS */
	{

.type = IIO_INTENSITY, .modified = 1, .channel2 = IIO_MOD_LIGHT_BOTH, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .scan_index = AP3216C_ALS, .scan_type = { .sign = 'u', .realbits = 16, .storagebits = 16, .endianness = IIO_LE, }, }, /* PS */ { .type = IIO_PROXIMITY, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .scan_index = AP3216C_PS, .scan_type = { .sign = 'u', .realbits = 10, .storagebits = 16, .endianness = IIO_LE, }, }, /* IR */ { .type = IIO_INTENSITY, .modified = 1, .channel2 = IIO_MOD_LIGHT_IR, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .scan_index = AP3216C_IR, .scan_type = { .sign = 'u', .realbits = 10, .storagebits = 16, .endianness = IIO_LE, }, }, }; static int ap3216c_read_als(struct ap3216c_data *data, int *val) { unsigned char reg[2]; int ret; ret = regmap_bulk_read(data->regmap, AP3216C_ALSDATALOW, reg, 2); if (ret) return ret; *val = ((int)reg[1] << 8) | reg[0]; return ret; } static int ap3216c_read_ps(struct ap3216c_data *data, int *val) { unsigned char reg[2]; int ret; ret = regmap_bulk_read(data->regmap, AP3216C_PSDATALOW, reg, 2); if (ret) return ret;

linux 驱动通知应用层_android linux内核层_android 驱动层与hal层

*val = ((int)(reg[1] & 0X3F) << 4) | (reg[0] & 0X0F); return ret; } static int ap3216c_read_ir(struct ap3216c_data *data, int *val) { unsigned char reg[2]; int ret; ret = regmap_bulk_read(data->regmap, AP3216C_IRDATALOW, reg, 2); if (ret) return ret; *val = ((int)reg[1] << 2) | (reg[0] & 0X03); return ret; } #define AP3216C_SCALE(range) (int)(((long long)range * 1000000) / 65535) static const int ap3216c_als_scale[] = {AP3216C_SCALE(23360), AP3216C_SCALE(5840), AP3216C_SCALE(1460), AP3216C_SCALE(365)}; static int ap3216c_read_als_scale(struct ap3216c_data *data, int *val) { unsigned int reg; int ret; ret = regmap_read(data->regmap, AP3216C_ALSCONFIG, &reg); if (ret) return ret; *val = ap3216c_als_scale[((reg & 0X30) >> 4)]; return ret; } static int ap3216c_write_als_scale(struct ap3216c_data *data, int val) { int i, ret = 0; for (i=0; i<ARRAY_SIZE(ap3216c_als_scale); ++i) { if (ap3216c_als_scale[i] == val) break; } if(i == ARRAY_SIZE(ap3216c_als_scale)) { ret = -EINVAL; } else { ret = regmap_write(data->regmap, AP3216C_ALSCONFIG, (unsigned char)(i<<4)); } return ret; } static int ap3216c_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct ap3216c_data *data = iio_priv(indio_dev); int ret = -EINVAL;

linux 驱动通知应用层_android 驱动层与hal层_android linux内核层

switch (mask) { case IIO_CHAN_INFO_RAW: switch (chan->type) { case IIO_INTENSITY: switch (chan->channel2) { case IIO_MOD_LIGHT_BOTH: mutex_lock(&data->lock); ret = ap3216c_read_als(data, val); mutex_unlock(&data->lock); if (ret) return ret; ret = IIO_VAL_INT; break; case IIO_MOD_LIGHT_IR: mutex_lock(&data->lock); ret = ap3216c_read_ir(data, val); mutex_unlock(&data->lock); if (ret) return ret; ret = IIO_VAL_INT; break; default: ret = -EINVAL; break; } break; case IIO_PROXIMITY: mutex_lock(&data->lock); ret = ap3216c_read_ps(data, val); mutex_unlock(&data->lock); if (ret) return ret; ret = IIO_VAL_INT; break; default: ret = -EINVAL; break; } break; case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_INTENSITY: mutex_lock(&data->lock); ret = ap3216c_read_als_scale(data, val2); mutex_unlock(&data->lock); if (ret) return ret; *val = 0; ret = IIO_VAL_INT_PLUS_MICRO; break; default: ret = -EINVAL; break; } break; default: ret = -EINVAL; break; } return ret; }

static const struct iio_info ap3216c_info = { .read_raw = ap3216c_read_raw, }; static int ap3216c_init(struct ap3216c_data *data) { struct device *dev = &data->client->dev; int als, ps, ir; int ret; ret = regmap_write(data->regmap, AP3216C_SYSTEMCONG, 0x04); // reset ap3216c if (ret) return ret; mdelay(50); // >=10ms ret = regmap_write(data->regmap, AP3216C_SYSTEMCONG, 0x03); // ALS and PS+IR functions once if (ret) return ret; ret = ap3216c_write_als_scale(data, ap3216c_als_scale[0]); // 23360 lux / Resolution bit if (ret) return ret; ret = regmap_write(data->regmap, AP3216C_PSLEDCONFIG, 0x13); // LED 1 pulse, LED driver ratio 100% if (ret) return ret; ap3216c_read_als(data, &als); ap3216c_read_ps(data, &ps); ap3216c_read_ir(data, &ir); dev_info(dev, "ALS=%d, PS=%d, IR=%dn", als, ps, ir); return 0; } static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct iio_dev *indio_dev; struct ap3216c_data *data; int ret; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; indio_dev->name = AP3216C_DRV_NAME; indio_dev->info = &ap3216c_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = ap3216c_channels; indio_dev->num_channels = ARRAY_SIZE(ap3216c_channels); indio_dev->available_scan_masks = ap3216c_scan_masks; data = iio_priv(indio_dev); data->indio_dev = indio_dev; data->client = client; mutex_init(&data->lock); i2c_set_clientdata(client, indio_dev); data->regmap = devm_regmap_init_i2c(client, &ap3216c_regmap_config); if (IS_ERR(data->regmap)) { dev_err(&client->dev, "regmap initialization failedn"); return PTR_ERR(data->regmap); } ret = ap3216c_init(data); if (ret) return ret; return iio_device_register(indio_dev); } static int ap3216c_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); iio_device_unregister(indio_dev); return 0; } static const struct of_device_id ap3216c_of_match[] = { { .compatible = "lsc,ap3216c" }, { }, }; MODULE_DEVICE_TABLE(of, ap3216c_of_match); static struct i2c_device_id ap3216c_id[] = { { "ap3216c", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, ap3216c_id); static struct i2c_driver ap3216c_driver = { .driver = { .owner = THIS_MODULE, .name = "ap3216c", .of_match_table = of_match_ptr(ap3216c_of_match), }, .probe = ap3216c_probe, .remove = ap3216c_remove, .id_table = ap3216c_id, }; module_i2c_driver(ap3216c_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sonboy"); MODULE_DESCRIPTION("Driver for AP3216C");

3. 设备树

这里示例,只需要i2c设备下添加我们的子设备。

&i2c {
	ap3216c@1e {
		compatible = "lsc,ap3216c";
		reg = <0x1e>;
	};
};

4. 运行

加载驱动打印如下信息,驱动加载成功。

进入/sys/bus/iio/devices/iio:device0目录,你的不一定是iio:device0。有如下文件,操作这些文件即可操作设备。

源码获取:

git clone https://github.com/Sonboy97/linux-drivers.git

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: iic 传感器
最后更新:2022年12月5日

Linux大神网

每日更新,欢迎收藏♥ 不积跬步无以至千里,加油,共勉。

点赞
< 上一篇
下一篇 >

Linux大神网

每日更新,欢迎收藏♥
不积跬步无以至千里,加油,共勉。

最新 热点 随机
最新 热点 随机
查看系统版本 linux “”的有关知识,不少人都会遇到这样的困境 Linux在内核中是如何记录进程资源的?你能从C语言源代码层面分析下吗? 【】原操作系统配备内核源代码,更不能进行内核模块实验 【Linux基础知识】与文件权限管理的Linux关系 linux/管理员管理员发布于5年前34(图) Linux和Unix操作系统之间有区别但也有联系?(一) Ubuntu系统如何升级和更新Linux内核版本?将推荐 Linux内核技术组成、组织和重要的数据结构等(组图) 【报错日志】一下升级linux内核的启动顺序为0 Linux终端窗口中输入mysql-V以显示MySQL版本信息sky 计算机操作系统全新版装系统盘点、理念与系统的优缺点 linux中常用的用户管理命令:1groups?列出当前用户所属 Linux下如何设置开机启动启动脚本?学算法 Linux中已经安装好了mysql命令 Linux系统用户系统上的三种类型的帐户的介绍 Linux下的开机启动设置方法是什么?脚本或服务 谷歌更新Linux内核构建的公共内核库:添加对kokoro作业的支持 linux下mysql中可以使用REVOKE语句来删除某个用户的权限 内核的角度来看,调用hotplug和通常的hotplug环境 Linux系统在开机的时候自动加载某些脚本或系统服务
Linux5.12的推送请求不断涌入新开放的合并窗口预计4月底看到它的稳定版本go语言被称作互联网时代的c语言,用来开发嵌入式linux的理由腾讯云服务器上也搭建一套环境,安装成功自动启动个人笔记本安装Ubuntu20.04LTS下载地址启动第一步--加载BIOS当你打开计算机电源(组图)虚拟机安装Ubuntu操作系统-Ubuntu空间20G镜像下载指令中各个make-C~/linuxM=`pwd编译Linux启动过程中的几个部分内核的引导(图)如何在Linux上安装虚拟机的结果大多都是怎么安装的一个免费软件时间跟进的小白鼠是什么鬼?专题计算机是如何启动的?、内核操作系统的启动流程学习Linux最简单、最实用的环境就是虚拟机环境(上)基于命令修改文件的权限命令-ld1.Linux磁盘分区和目录Linux发行版本之间的差别很少?国内性价比很高的Linux虚拟主机系统安装的流程是什么?Linux下修改文件权限的权限与所有权的实现就显得很有必要linux到底难不难学呢?推荐可以查看Linux命令大全Linux中修改文件权限的命令、创建者所在组、所有人Linux的内核放在了哪里?/boot的启动目录一览阿里云>社区>主题地图S>查看存储推荐
中科红旗(北京)信息科技有限公司研发的Linux桌面操作系统社区预览版 Linux内核技术交流群--一下Linux的核心目录结构 1.Linux磁盘分区和目录Linux发行版本之间的差别很少? 打开电脑命令行快捷键进入电脑DOS命令界面方法:Command开始菜单 Windows环境中远程连接Linux服务器_轻量 《深入linux设备驱动程序内核机制》(1)_社会万象_光明网(图) Linux系统的修改权限与默认权限的分类及处理方法 Linux下的安装zip解压功能及安装unzip教程 【Linux运维学习必看书籍推荐】——Linux运维大环境说明 【Linux基础知识】Linux下的共享库和动态库 在文档中查找字符串用grep命令的使用:几个 【Linux基础知识】Linux系统的启动流程经历(二) 10.5内核定时器编程TIMER_SOFTIRQ软中断,运行当前处理器CPU上到期的所有定时器 巨幕智屏怎么看电视直播给电视成功安装当贝市场 Linux计算机上使用ip命令来找到目标IP地址的方法 df显示指定磁盘文件和目录的磁盘使用空间命令参数 Ubuntu上使用的默认浏览器为Firefox,该怎么安装? linux虚拟机的安装步骤是什么?虚拟机和服务器的区别 入门到就业线上直播课:linux查询端口的使用方法 Linux中国荣誉研究生申请之cron定时器
标签聚合
电脑 虚拟机 linux服务器 命令模式 linux系统 sudo 文件目录 shell 软件 unix
书籍
课程
技术群
技术干货大合集↓
  • 2023年2月 / 26篇
  • 2023年1月 / 161篇
  • 2022年12月 / 187篇
  • 2022年11月 / 76篇

COPYRIGHT © 2023 linuxgod.net ALL RIGHTS RESERVED.