RK3568 android11 debugging light sensor module

1. Introduction

The light sensor module is a sensor used to detect light intensity. It senses the light level of the surrounding environment and converts it into an electrical signal output. The working principle of the light sensing module is based on the photoelectric effect, and there are mainly the following types:

  1. Photoresistor (LDR): The photoresistor is a sensor based on the photoelectric effect, and its resistance value changes according to changes in light intensity. When the light intensity increases, the resistance value of the photoresistor decreases and vice versa. By measuring the resistance value of the photoresistor, information on the intensity of light can be obtained.

  2. Photodiode: A photodiode is a diode that converts light energy into electrical energy. When light strikes a photodiode, the photons excite electrons, causing them to generate an electric current in the PN junction. By measuring the current on the photodiode, information about the light intensity can be obtained.

  3. Phototransistor: Phototransistor is a photodiode with amplification function. It can convert light energy into electrical energy and amplify the output current. Phototransistors generally have higher sensitivity and response speed and are suitable for applications requiring higher sensitivity.

  4. Photocapacitor: Photocapacitor is a capacitive sensor based on the photoelectric effect. When light strikes a photocapacitive sensor, the photons excite electrons, causing them to accumulate charge in the capacitor. By measuring the level of charge accumulation on the capacitor, information about the light intensity can be obtained.

These light-sensing modules can provide light intensity information through an analog voltage output or a digital interface output (such as I2C or SPI). They are widely used in fields such as automatic lighting systems, environmental monitoring, light adjustment and photosensitive control.


2. Drive part

Debug the light sensor module (the three corners are connected to the power supply VCC, ground GND, and ADC respectively), 光线越亮, 屏越亮;光线越暗, 屏越暗(亮度不低于50%).

1. Add ADC driver

Source code path: 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, about iio_read_channel_processed function

The implementation of the iio_read_channel_processed` function is completed in the IIO subsystem. Its main function is to read the raw value of the specified IIO channel and convert it to the value after engineering units. Here is the pseudo code for this function:

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;
}

In this function, the iio_read_channel_raw function is first called to read the original value of the IIO channel and save it in the raw_val variable. Then, get the scale factor and offset of the IIO device by calling the iio_channel_get_scale and iio_channel_get_offset functions. Scale factor and offset are parameters used to convert the original value to engineering units. Finally, multiply the original value by the scale factor, add the offset, and round to an integer using the round function to get the processed value and save it in the val variable.

It should be noted that the iio_read_channel_processed function can only read processed values ​​and cannot read original values. If you need to read raw values, you can use the iio_read_channel_raw function.

1.2 iio operating instructions

1> Get AD channel

struct iio_channel *chan; //Define the IIO channel structure
chan = iio_channel_get(&pdev->dev,xxx); //Get the IIO channel structure a>

Note: iio_channel_get obtains the IIO channel structure through the parameter pdev passed in by the probe function. The probe function is as follows:

2> Read the raw data collected by AD

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

Call the iio_read_channel_raw function to read the original data collected by AD and store it in val.
3> Calculate the collected voltage
Use the standard voltage to convert the AD converted value into the voltage value required by the user. The calculation formula is as follows:

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

  • Vref is the standard voltage
  • n is the number of digits for AD conversion
  • Vresult is the collection voltage required by the user
  • raw is the raw data collected by AD

2. Add Makefile

Source code path: 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. Add device nodes in dts

Source code path: 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";

After the driver part is added, it is compiled and burned. After entering the system, a /sys/adc_value/adc_value node will appear, indicating that the creation is successful. Cat /sys/adc_value/adc_value can see the node status.


Three, frameworks part

Source code path: 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;

Guess you like

Origin blog.csdn.net/weixin_45639314/article/details/133862775