RK3568 android11 调试光感模块

一,简介

光感模块是一种用于检测光照强度的传感器。它可以感知周围环境的光照水平,并将其转换为电信号输出。光感模块的工作原理基于光电效应,主要有以下几种类型:

  1. 光敏电阻(LDR):光敏电阻是一种基于光电效应的传感器,其电阻值会根据光照强度的变化而变化。当光照强度增加时,光敏电阻的电阻值会减小,反之亦然。通过测量光敏电阻的电阻值,可以得到光照强度的信息。

  2. 光电二极管(Photodiode):光电二极管是一种能够将光能转化为电能的二极管。当光照射到光电二极管上时,光子会激发电子,使其在PN结中产生电流。通过测量光电二极管上的电流,可以得到光照强度的信息。

  3. 光电三极管(Phototransistor):光电三极管是一种具有放大功能的光电二极管。它可以将光能转化为电能,并放大输出的电流。光电三极管通常具有更高的灵敏度和响应速度,适用于需要较高灵敏度的应用。

  4. 光电容传感器(Photocapacitor):光电容传感器是一种基于光电效应的电容传感器。当光照射到光电容传感器上时,光子会激发电子,使其在电容器中产生电荷积累。通过测量电容器上的电荷积累水平,可以得到光照强度的信息。

这些光感模块可以通过模拟电压输出或数字接口输出(例如I2C或SPI)来提供光照强度的信息。它们广泛应用于自动照明系统、环境监测、光线调节和光敏控制等领域。


二,驱动部分

调试光感模块(三个角分别接供电VCC、地GND、ADC),光线越亮, 屏越亮;光线越暗, 屏越暗(亮度不低于50%)

1.添加ADC驱动

源码路径:kernel/drivers/input/keyboard/adc0_driver.c

/*
* Input driver for resistor ladder connected on ADC
*
* Copyright (c) 2016 Alexandre Belloni
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/


#include <linux/err.h>
#include <linux/iio/consumer.h>
#include <linux/iio/types.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>

/*----<fy:add  api for app read adc value>---------------*/
struct iio_channel *adc_channel;

static ssize_t adc_value_read(struct device *dev, struct device_attribute *attr,char *buf)
{
    
    
       //return sprintf(buf, "%d\n",sunxi_keyboard_read_data());
       int read_value = 0;
           
           if(adc_channel !=NULL)
                iio_read_channel_processed(adc_channel, &read_value);
            
        return sprintf(buf, "%d\n",read_value);
}

static DEVICE_ATTR(adc_value, S_IRUGO|S_IWUSR|S_IWGRP,adc_value_read, NULL);

static struct attribute *adc_value_attributes[] = {
    
    
       &dev_attr_adc_value.attr,
       NULL
};

static struct attribute_group adc_value_attribute_group = {
    
    
       .attrs = adc_value_attributes
};
/*----<fy:end>---------------------------------------*/

static int adc0_driver_probe(struct platform_device *pdev)
{
    
    
    struct device *dev = &pdev->dev;

    struct kobject *dev_kobj;
    int err =-1;

    printk("adc_value:adc_keys_probe 1\n");

    adc_channel = devm_iio_channel_get(dev, "adc0_chan");
    if (IS_ERR(adc_channel))
        return PTR_ERR(adc_channel);
    printk("adc_value:adc_keys_probe 2\n");


    /*fy add kobj  to create    sysfs of adc_value>*/

    dev_kobj = kobject_create_and_add("adc_value",NULL);

    if(dev_kobj != NULL)
            err = sysfs_create_group(dev_kobj,&adc_value_attribute_group);
    
    if (err < 0)
    {
    
    
            printk("adc_value: sysfs_create_group err\n");
    }
    /*fy: end >*/

    return 0;
}

#ifdef CONFIG_OF
static const struct of_device_id adc0_driver_of_match[] = {
    
    
    {
    
     .compatible = "adc0_driver", },
    {
    
     }
};
MODULE_DEVICE_TABLE(of, adc0_driver_of_match);
#endif

static struct platform_driver __refdata adc0_driver = {
    
    
    .driver = {
    
    
        .name = "adc0_driver",
        .of_match_table = of_match_ptr(adc0_driver_of_match),
    },
    .probe = adc0_driver_probe,
};
module_platform_driver(adc0_driver);

MODULE_AUTHOR("Alexandre Belloni <[email protected]>");
MODULE_DESCRIPTION("Input driver for resistor ladder connected on ADC");
MODULE_LICENSE("GPL v2");
1.1,关于iio_read_channel_processed函数

iio_read_channel_processed` 函数的实现是在 IIO 子系统中完成的。它的主要作用是读取指定 IIO 通道的原始值,并将其转换为工程单位后的值。下面是该函数的伪代码:

int iio_read_channel_processed(struct iio_channel *chan, int *val)
{
    
    
    int ret;
    long long raw_val;
    double scale, offset;

    // 读取 IIO 通道的原始值
    ret = iio_read_channel_raw(chan, &raw_val);
    if (ret < 0)
        return ret;

    // 获取 IIO 设备的比例因子和偏移量
    scale = iio_channel_get_scale(chan);
    offset = iio_channel_get_offset(chan);

    // 将原始值转换为工程单位后的值
    *val = (int)round((raw_val * scale) + offset);

    return 0;
}

在这个函数中,首先调用 iio_read_channel_raw函数读取 IIO 通道的原始值,并将其保存在 raw_val变量中。然后,通过调用 iio_channel_get_scale和 iio_channel_get_offset函数获取 IIO 设备的比例因子和偏移量。比例因子和偏移量是用于将原始值转换为工程单位后的值的参数。最后,将原始值乘以比例因子,加上偏移量,并使用 round函数四舍五入为整数,得到处理后的值,并将其保存在 val 变量中。

需要注意的是,iio_read_channel_processed 函数只能读取处理后的值,而无法读取原始值。如果需要读取原始值,可以使用 iio_read_channel_raw 函数。

1.2 iio操作说明

1> 获取AD通道

struct iio_channel *chan; //定义 IIO 通道结构体
chan = iio_channel_get(&pdev->dev,xxx); //获取 IIO 通道结构体

注: iio_channel_get 通过 probe 函数传进来的参数 pdev 获取 IIO通道结构体,probe 函数如下:

2> 读取AD采集到的原始数据

int val,ret;
ret = iio_read_channel_raw(chan, &val);

调用 iio_read_channel_raw 函数读取 AD 采集的原始数据并存入 val 中。
3> 计算采集到的电压
使用标准电压将 AD 转换的值转换为用户所需要的电压值。其计算公式如下:

Vref / (2^n-1) = Vresult / raw
例如,标准电压为 1.8V,AD 采集位数为 10 位,AD 采集到的原始数据为 568,则: Vresult = (1800mv * 568) / 1023

  • Vref 为标准电压
  • n 为 AD 转换的位数
  • Vresult 为用户所需要的采集电压
  • raw 为 AD 采集的原始数据

2.添加Makefile

源码路径:kernel/drivers/input/keyboard/Makefile

diff --git a/kernel/drivers/input/keyboard/Makefile b/kernel/drivers/input/keyboard/Makefile
index 182e929..0ada96c 100644
--- a/kernel/drivers/input/keyboard/Makefile
+++ b/kernel/drivers/input/keyboard/Makefile
@@ -67,3 +67,4 @@ obj-$(CONFIG_KEYBOARD_TM2_TOUCHKEY)    += tm2-touchkey.o
obj-$(CONFIG_KEYBOARD_TWL4030)        += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD)        += xtkbd.o
obj-$(CONFIG_KEYBOARD_W90P910)        += w90p910_keypad.o
+obj-y          += adc0_driver.o

3.dts中添加设备节点

源码路径:kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi

diff --git a/kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi
index 0cf8a59..3384fe1 100644
--- a/kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi
+++ b/kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi
@@ -291,6 +291,13 @@
         };
     };

+    adc:adc0_driver {
    
    
+            compatible = "adc0_driver";
+            io-channels = <&saradc 4>;
+            io-channel-names = "adc0_chan";
+            //keyup-threshold-microvolt = <1800000>;
+    };

     firmware {
    
    
         firmware_android: android {
    
    
             compatible = "android,firmware";

驱动部分添加完成后编译烧录, 在进入系统后,会出现一个 /sys/adc_value/adc_value节点,表示创建成功。cat /sys/adc_value/adc_value可看到节点状态。


三,frameworks部分

源码路径:frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java

diff --git a/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index 1f41038..3298c78 100644
--- a/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -39,13 +39,40 @@ import java.io.PrintWriter;
import javax.inject.Inject;
-public class SystemUIService extends Service {
    
    
+import android.app.smdt.SmdtManagerNew;
+import android.app.smdt.SmdtManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStream;
+import android.content.Context;
+public class SystemUIService extends Service {
    
    
+    private static final String TAG="SystemUIService";
     private final Handler mMainHandler;
     private final DumpHandler mDumpHandler;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final LogBufferFreezer mLogBufferFreezer;
     private final BatteryStateNotifier mBatteryStateNotifier;
+    private SmdtManager mSmdt=null;
+    private SmdtManagerNew smdtManagerNew;
+    private Context mContext;
     @Inject
     public SystemUIService(
@@ -72,6 +99,13 @@ public class SystemUIService extends Service {
    
    
         // Finish initializing dump logic
         mLogBufferFreezer.attach(mBroadcastDispatcher);
+        mContext=this;
+        if(mSmdt==null){
    
    
+             mSmdt = new SmdtManager(mContext);
+              smdtManagerNew = SmdtManagerNew.getInstance(mContext);
+        }
+        mHandler.sendEmptyMessageDelayed(1001,100);
+
         // If configured, set up a battery notification
         if (getResources().getBoolean(R.bool.config_showNotificationForUnknownBatteryState)) {
    
    
             mBatteryStateNotifier.startListening();
@@ -103,6 +137,87 @@ public class SystemUIService extends Service {
    
    
                 UserHandle.SYSTEM);
     }
+private Handler mHandler=new Handler(){
    
    
+    @Override
+        public void dispatchMessage(Message msg) {
    
    
+            switch (msg.what){
    
    
+                case 1001://wifi
+                    Log.d(TAG, "dispatchMessage: fy==========value="+cccccss());//("cat /sys/adc_value/adc_value"));
+                    readLightSenseValue();
+                    mHandler.removeMessages(1001);
+                    mHandler.sendEmptyMessageDelayed(1001,500);
+                    break;
+                case 1002://
+
+                    break;
+                default:
+                    break;
+            }
+        }
+};
+private int cccccss(){
    
    //get light sensor value
+    String a="0";
+    try {
    
    
+        BufferedReader bufWriter = null;
+        bufWriter = new BufferedReader(new FileReader("/sys/adc_value/adc_value"));
+        a=bufWriter.readLine();
+        bufWriter.close();
+
+    } catch (IOException e) {
    
    
+        e.printStackTrace();
+        Log.e("aaa","can't write the point" );
+    }
+    return Integer.parseInt(a);
+}
+
+//光线越亮, 屏越亮;光线越暗, 屏越暗(亮度不低于50%)
+private int oldvalue = 1800;
+private int time = 0;
+private int readLightSenseValue(){
    
    
+    int result=0;
+    int value=cccccss();
+    Log.d(TAG, "dispatchMessage: fy==========value="+value);
+    if(Math.abs(value - oldvalue) < 10)
+        return result;
+    time ++;
+    if(time < 2)
+      return result;
+    time = 0;
+
+    Log.d(TAG, "readLightSenseValue: adc value="+value + " oldvalue="+oldvalue);
+    oldvalue = value;
+    float fv = ((float)value - 1646) / 150;
+    Log.d(TAG, "readLightSenseValue: fv="+fv);
+    value=(int)(fv*255);
+    if(value < 10)
+        value = 10;
+    
+    //value = (int)(((255.0 - 125.0) / 10.0 ) * value + 125 );
+    if(value > 255)
+        value = 255;
+    Log.d(TAG, "smdt set lvds Brightness " + value);
+    setLcdBrightness(value);
+    mSmdt.setBrightness(getContentResolver(), value);
+    return result;
+}
+
+/* //光线越暗 屏越亮,光线越亮 屏越暗(亮度不低于50%)
+private int oldvalue = 1800;
+private int time = 0;
+private int readLightSenseValue(){
+    int result=0;
+    int value=cccccss();
+    if(Math.abs(value - oldvalue) < 40)
+        return result;
+    time ++;
+    if(time < 3)
+      return result;
+    time = 0;

+    Log.d(TAG, "readLightSenseValue: adc value="+value + " oldvalue="+oldvalue);
+    oldvalue = value;
+    value = (value - 900) / 40;
+    Log.d(TAG, "readLightSenseValue: value="+value);
+    if(value > 10)
+        value = 10;
+    setLcdBrightness(value);
+    value = (int)(((255.0 - 125.0) / 10.0 ) * value + 125 );
+    if(value > 255)
+        value = 255;
+    Log.d(TAG, "smdt set lvds Brightness " + value);
+    mSmdt.setBrightness(getContentResolver(), value);
+    return result;
+}
+*/

+private void setLcdBrightness(int bri){
    
    
+    smdtManagerNew.disp_setLcdBackLight(0, bri, 0, false);
+

     @Override
     public IBinder onBind(Intent intent) {
    
    
         return null;

猜你喜欢

转载自blog.csdn.net/weixin_45639314/article/details/133862775