rk3326s linux平台 kernel4.4。项目中用到光距离感应器stk3332,需要调通驱动。
先看硬件原理图:
与主控接口为I2C1,dts中配置:
ls_stk3x1x: light@47 {
compatible = "ls_stk3332";
status = "okay";
reg = <0x47>;
type = <SENSOR_TYPE_LIGHT>;
irq_enable = <0>;
als_threshold_high = <100>;
als_threshold_low = <10>;
als_ctrl_gain = <2>; /* 0:x1 1:x4 2:x16 3:x64 */
poll_delay_ms = <100>;
layout = <1>;
};
ps_stk3x1x: proximity@47 {
compatible = "ps_stk3332";
status = "okay";
reg = <0x47>;
type = <SENSOR_TYPE_PROXIMITY>;
pinctrl-names = "default";
pinctrl-0 = <&stk3311_irq_gpio>;
irq-gpio = <&gpio3 RK_PB0 IRQ_TYPE_LEVEL_LOW>;
irq_enable = <1>;
ps_threshold_high = <0x200>;
ps_threshold_low = <0x100>;
ps_ctrl_gain = <3>; /* 0:x1 1:x4 2:x16 3:x64 */
ps_led_current = <3>; /* 0:12.5mA 1:25mA 2:50mA 3:100mA */
poll_delay_ms = <100>;
};
dts需要按照rk的sensor架构来写,具体看kernel\drivers\input\sensors\sensor-dev.c中代码,lsensor和psensor是分开的。LIGHT_ID_STK3332 和PROXIMITY_ID_STK3332需要加入sensor-dev.h文件中。
驱动代码:
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Kay Guo <kay.guo@rock-chips.com>
*/
#include <linux/atomic.h>
#include <linux/delay.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/freezer.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/of_gpio.h>
#include <linux/sensor-dev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#define STK_STATE 0x00
#define PS_CTRL 0x01
#define ALS_CTRL1 0x02
#define LED_CTRL 0x03
#define INT_CTRL1 0x04
#define STK_WAIT 0x05
#define THDH1_PS 0x06
#define THDH2_PS 0x07
#define THDL1_PS 0x08
#define THDL2_PS 0x09
#define THDH1_ALS 0x0A
#define THDH2_ALS 0x0B
#define THDL1_ALS 0x0C
#define THDL2_ALS 0x0D
#define STK_FLAG 0x10
#define DATA1_PS 0x11
#define DATA2_PS 0x12
#define DATA1_ALS 0x13
#define DATA2_ALS 0x14
#define DATA1_C 0x1B
#define DATA2_C 0x1C
#define DATA1_PS_OFFSET 0x1D
#define DATA2_PS_OFFSET 0x1E
#define DATA_CTRL1 0x20
#define DATA_CTRL2 0x21
#define DATA_CTRL3 0x22
#define DATA_CTRL4 0x23
#define STKPDT_ID 0x3E
#define STK_RESERVED 0x3F
#define ALS_CTRL2 0x4E
#define INTELLI_WAIT 0x4F
#define SOFT_RESET 0x80
#define PSPD_CTRL 0xA1
#define INT_CTRL2 0xA5
/* STK_STATE 0x00 */
#define PS_DISABLE (0 << 0)
#define PS_ENABLE (1 << 0)
#define ALS_DISABLE (0 << 1)
#define ALS_ENABLE (1 << 1)
#define WAIT_DISABLE (0 << 2)
#define WAIT_ENABLE (1 << 2)
#define INTELLI_DISABLE (0 << 3)
#define INTELLI_ENABLE (1 << 3)
#define CTAUTOK_DISABLE (0 << 4)
#define CTAUTOK_ENABLE (1 << 4)
/* PS/GS_CTRL 0x01 */
#define PS_IT_96US (0 << 0)
#define PS_IT_192US (1 << 0)
#define PS_IT_384US (2 << 0)
#define PS_IT_768US (3 << 0)
#define PS_IT_1MS54 (4 << 0)
#define PS_IT_3MS07 (5 << 0)
#define PS_IT_6MS14 (6 << 0)
#define PS_GAIN_1G (0 << 4)
#define PS_GAIN_2G (1 << 4)
#define PS_GAIN_4G (2 << 4)
#define PS_GAIN_8G (3 << 4)
#define PS_PRST_1T (0 << 6)
#define PS_PRST_2T (1 << 6)
#define PS_PRST_4T (2 << 6)
#define PS_PRST_16T (3 << 6)
/* ALS_CTRL1 0x02 */
#define ALS_REFT_MS (1 << 0)/* [3:0] 25 ms, default value is 50ms */
#define ALS_GAIN_1G (0 << 4)
#define ALS_GAIN_4G (1 << 4)
#define ALS_GAIN_16G (2 << 4)
#define ALS_GAIN_64G (3 << 4)
#define ALS_PRST_1T (0 << 6)
#define ALS_PRST_2T (1 << 6)
#define ALS_PRST_4T (2 << 6)
#define ALS_PRST_8T (3 << 6)
/* LED_CTRL 0x03 */
#define LED_REFT_US 0x03 /* [5:0] 2.89us , default value is 0.185ms */
#define CTIR_DISABLE (0 << 0)
#define CTIR_ENABLE (1 << 0)
#define CTIRFC_DISABLE (0 << 1)
#define CTIRFC_ENABLE (1 << 1)
#define LED_CUR_12MA (2 << 5)
#define LED_CUR_25MA (3 << 5)
#define LED_CUR_50MA (4 << 5)
#define LED_CUR_100MA (5 << 5)
#define LED_CUR_150MA (6 << 5)
/* INT 0x04 */
#define PS_INT_DISABLE (0 << 0)
#define PS_INT_ENABLE (1 << 0)
#define PS_INT_ENABLE_FLGNFH (2 << 0)
#define PS_INT_ENABLE_FLGNFL (3 << 0)
#define PS_INT_MODE_ENABLE (4 << 0)
#define PS_INT_ENABLE_THL (5 << 0)
#define PS_INT_ENABLE_THH (6 << 0)
#define PS_INT_ENABLE_THHL (7 << 0)
#define ALS_INT_DISABLE (0 << 3)
#define ALS_INT_ENABLE (1 << 3)
#define INT_CTRL_PS_OR_LS (0 << 7)
#define INT_CTRL_PS_AND_LS (1 << 7)
/* FLAG 0x10 */
#define STK_FLAG_NF (1 << 0)
#define STK_FLAG_INPS_INT (1 << 1)
#define STK_FLAG_ALS_STATE (1 << 2)
#define STK_FLAG_PS_INT (1 << 4)
#define STK_FLAG_ALS_INT (1 << 5)
#define STK_FLAG_PSDR (1 << 6)
#define STK_FLAG_ALSDR (1 << 7)
static int sensor_active(struct i2c_client *client, int enable, int rate)
{
struct sensor_private_data *sensor =
(struct sensor_private_data *)i2c_get_clientdata(client);
int result = 0;
int status = 0;
sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg);
if (!enable) {
status = ~ALS_ENABLE;
sensor->ops->ctrl_data &= status;
} else {
status |= ALS_ENABLE;
sensor->ops->ctrl_data |= status;
}
dev_dbg(&client->dev, "reg=0x%x, reg_ctrl=0x%x, enable=%d\n",
sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable);
result = sensor_write_reg(client, sensor->ops->ctrl_reg,
sensor->ops->ctrl_data);
if (result)
dev_err(&client->dev, "%s:fail to active sensor\n", __func__);
return result;
}
static int sensor_init(struct i2c_client *client)
{
struct sensor_private_data *sensor =
(struct sensor_private_data *)i2c_get_clientdata(client);
struct device_node *np = client->dev.of_node;
int als_val = 0;
int val = 0;
int ret = 0;
ret = sensor->ops->active(client, 0, 0);
if (ret) {
dev_err(&client->dev, "%s:sensor active fail\n", __func__);
return ret;
}
sensor->status_cur = SENSOR_OFF;
ret = of_property_read_u32(np, "als_threshold_low", &als_val);
if (ret)
dev_err(&client->dev, "%s:Unable to read als_threshold_low\n",
__func__);
ret = sensor_write_reg(client, THDL1_ALS,
(unsigned char)(als_val >> 8));
if (ret) {
dev_err(&client->dev, "%s:write THDL1_ALS fail\n", __func__);
return ret;
}
ret = sensor_write_reg(client, THDL2_ALS, (unsigned char)als_val);
if (ret) {
dev_err(&client->dev, "%s:write THDL1_ALS fail\n", __func__);
return ret;
}
ret = of_property_read_u32(np, "als_threshold_high", &als_val);
if (ret)
dev_err(&client->dev, "%s:Unable to read als_threshold_high\n",
__func__);
ret = sensor_write_reg(client, THDH1_ALS,
(unsigned char)(als_val >> 8));
if (ret) {
dev_err(&client->dev, "%s:write THDH1_ALS fail\n", __func__);
return ret;
}
ret = sensor_write_reg(client, THDH2_ALS, (unsigned char)als_val);
if (ret) {
dev_err(&client->dev, "%s:write THDH1_ALS fail\n", __func__);
return ret;
}
ret = of_property_read_u32(np, "als_ctrl_gain", &als_val);
if (ret)
dev_err(&client->dev, "%s:Unable to read als_ctrl_gain\n",
__func__);
ret = sensor_write_reg(client, ALS_CTRL1,
(unsigned char)((als_val << 4) | ALS_REFT_MS));
if (ret) {
dev_err(&client->dev, "%s:write ALS_CTRL fail\n", __func__);
return ret;
}
val = sensor_read_reg(client, INT_CTRL1);
val &= ~INT_CTRL_PS_AND_LS;
if (sensor->pdata->irq_enable)
val |= ALS_INT_ENABLE;
else
val &= ~ALS_INT_ENABLE;
ret = sensor_write_reg(client, INT_CTRL1, val);
if (ret) {
dev_err(&client->dev, "%s:write INT_CTRL1 fail\n", __func__);
return ret;
}
return ret;
}
static int light_report_value(struct input_dev *input, int data)
{
unsigned char index = 0;
if (data <= 100) {
index = 0;
goto report;
} else if (data <= 1600) {
index = 1;
goto report;
} else if (data <= 2250) {
index = 2;
goto report;
} else if (data <= 3200) {
index = 3;
goto report;
} else if (data <= 6400) {
index = 4;
goto report;
} else if (data <= 12800) {
index = 5;
goto report;
} else if (data <= 26000) {
index = 6;
goto report;
} else {
index = 7;
goto report;
}
report:
input_report_abs(input, ABS_MISC, index);
input_sync(input);
return index;
}
static int sensor_report_value(struct i2c_client *client)
{
struct sensor_private_data *sensor =
(struct sensor_private_data *)i2c_get_clientdata(client);
int result = 0;
int value = 0;
int index = 0;
char buffer[2] = { 0 };
if (sensor->ops->read_len < 2) {
dev_err(&client->dev, "%s:length is error, len=%d\n", __func__,
sensor->ops->read_len);
return -EINVAL;
}
buffer[0] = sensor->ops->read_reg;
result = sensor_rx_data(client, buffer, sensor->ops->read_len);
if (result) {
dev_err(&client->dev, "%s:sensor read data fail\n", __func__);
return result;
}
value = (buffer[0] << 8) | buffer[1];
index = light_report_value(sensor->input_dev, value);
dev_dbg(&client->dev, "%s result=0x%x, index=%d\n",
sensor->ops->name, value, index);
if (sensor->pdata->irq_enable && sensor->ops->int_status_reg) {
value = sensor_read_reg(client, sensor->ops->int_status_reg);
if (value & STK_FLAG_ALS_INT) {
value &= ~STK_FLAG_ALS_INT;
result = sensor_write_reg(client,
sensor->ops->int_status_reg,
value);
if (result) {
dev_err(&client->dev, "write status reg error\n");
return result;
}
}
}
return result;
}
static struct sensor_operate light_stk3332_ops = {
.name = "ls_stk3332",
.type = SENSOR_TYPE_LIGHT,
.id_i2c = LIGHT_ID_STK3332,
.read_reg = DATA1_ALS,
.read_len = 2,
.id_reg = SENSOR_UNKNOW_DATA,
.id_data = SENSOR_UNKNOW_DATA,
.precision = 16,
.ctrl_reg = STK_STATE,
.int_status_reg = STK_FLAG,
.range = { 100, 65535 },
.brightness = { 10, 255 },
.trig = IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
.active = sensor_active,
.init = sensor_init,
.report = sensor_report_value,
};
static struct sensor_operate *light_get_ops(void)
{
return &light_stk3332_ops;
}
static int __init light_stk3332_init(void)
{
struct sensor_operate *ops = light_get_ops();
int result = 0;
int type = ops->type;
result = sensor_register_slave(type, NULL, NULL, light_get_ops);
// printk("stk3332 init success!");
return result;
}
static void __exit light_stk3332_exit(void)
{
struct sensor_operate *ops = light_get_ops();
int type = ops->type;
sensor_unregister_slave(type, NULL, NULL, light_get_ops);
// printk("stk3332 exit success!");
}
// static int light_stk3332_probe(struct i2c_client *client,
// const struct i2c_device_id *devid)
// {
// return sensor_register_device(client, NULL, devid, &light_stk3332_ops);
// }
// static int light_stk3332_remove(struct i2c_client *client)
// {
// return sensor_unregister_device(client, NULL, &light_stk3332_ops);
// }
// static const struct i2c_device_id light_stk3332_id[] = {
// { "ls_stk3332", LIGHT_ID_STK3332 },
// {}
// };
// static struct i2c_driver light_stk3332_driver = {
// .probe = light_stk3332_probe,
// .remove = light_stk3332_remove,
// .shutdown = sensor_shutdown,
// .id_table = light_stk3332_id,
// .driver = {
// .name = "light_stk3332",
// #ifdef CONFIG_PM
// .pm = &sensor_pm_ops,
// #endif
// },
// };
// module_i2c_driver(light_stk3332_driver);
module_init(light_stk3332_init);
module_exit(light_stk3332_exit);
MODULE_AUTHOR("Kay Guo <kay.guo@rock-chips.com>");
MODULE_DESCRIPTION("stk3332 light driver");
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*
* Author: Kay Guo <kay.guo@rock-chips.com>
*/
#include <linux/atomic.h>
#include <linux/delay.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/freezer.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/of_gpio.h>
#include <linux/sensor-dev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#define STK_STATE 0x00
#define PS_CTRL 0x01
#define ALS_CTRL1 0x02
#define LED_CTRL 0x03
#define INT_CTRL1 0x04
#define STK_WAIT 0x05
#define THDH1_PS 0x06
#define THDH2_PS 0x07
#define THDL1_PS 0x08
#define THDL2_PS 0x09
#define THDH1_ALS 0x0A
#define THDH2_ALS 0x0B
#define THDL1_ALS 0x0C
#define THDL2_ALS 0x0D
#define STK_FLAG 0x10
#define DATA1_PS 0x11
#define DATA2_PS 0x12
#define DATA1_ALS 0x13
#define DATA2_ALS 0x14
#define DATA1_C 0x1B
#define DATA2_C 0x1C
#define DATA1_PS_OFFSET 0x1D
#define DATA2_PS_OFFSET 0x1E
#define DATA_CTRL1 0x20
#define DATA_CTRL2 0x21
#define DATA_CTRL3 0x22
#define DATA_CTRL4 0x23
#define STKPDT_ID 0x3E
#define STK_RESERVED 0x3F
#define ALS_CTRL2 0x4E
#define INTELLI_WAIT 0x4F
#define SOFT_RESET 0x80
#define PSPD_CTRL 0xA1
#define INT_CTRL2 0xA5
/* STK_STATE 0x00 */
#define PS_DISABLE (0 << 0)
#define PS_ENABLE (1 << 0)
#define ALS_DISABLE (0 << 1)
#define ALS_ENABLE (1 << 1)
#define WAIT_DISABLE (0 << 2)
#define WAIT_ENABLE (1 << 2)
#define INTELLI_DISABLE (0 << 3)
#define INTELLI_ENABLE (1 << 3)
#define CTAUTOK_DISABLE (0 << 4)
#define CTAUTOK_ENABLE (1 << 4)
/* PS/GS_CTRL 0x01 */
#define PS_IT_96US (0 << 0)
#define PS_IT_192US (1 << 0)
#define PS_IT_384US (2 << 0)
#define PS_IT_768US (3 << 0)
#define PS_IT_1MS54 (4 << 0)
#define PS_IT_3MS07 (5 << 0)
#define PS_IT_6MS14 (6 << 0)
#define PS_GAIN_1G (0 << 4)
#define PS_GAIN_2G (1 << 4)
#define PS_GAIN_4G (2 << 4)
#define PS_GAIN_8G (3 << 4)
#define PS_PRST_1T (0 << 6)
#define PS_PRST_2T (1 << 6)
#define PS_PRST_4T (2 << 6)
#define PS_PRST_16T (3 << 6)
/* ALS_CTRL1 0x02 */
#define ALS_REFT_MS (1 << 0)/* [3:0] 25 ms, default value is 50ms */
#define ALS_GAIN_1G (0 << 4)
#define ALS_GAIN_4G (1 << 4)
#define ALS_GAIN_16G (2 << 4)
#define ALS_GAIN_64G (3 << 4)
#define ALS_PRST_1T (0 << 6)
#define ALS_PRST_2T (1 << 6)
#define ALS_PRST_4T (2 << 6)
#define ALS_PRST_8T (3 << 6)
/* LED_CTRL 0x03 */
#define LED_CTIR_EN 0x03 /* [5:0] 2.89us , default value is 0.185ms */
#define CTIR_DISABLE (0 << 0)
#define CTIR_ENABLE (1 << 0)
#define CTIRFC_DISABLE (0 << 1)
#define CTIRFC_ENABLE (1 << 1)
#define LED_CUR_12MA (2 << 5)
#define LED_CUR_25MA (3 << 5)
#define LED_CUR_50MA (4 << 5)
#define LED_CUR_100MA (5 << 5)
#define LED_CUR_150MA (6 << 5)
/* INT 0x04 */
#define PS_INT_DISABLE (0 << 0)
#define PS_INT_ENABLE (1 << 0)
#define PS_INT_ENABLE_FLGNFH (2 << 0)
#define PS_INT_ENABLE_FLGNFL (3 << 0)
#define PS_INT_MODE_ENABLE (4 << 0)
#define PS_INT_ENABLE_THL (5 << 0)
#define PS_INT_ENABLE_THH (6 << 0)
#define PS_INT_ENABLE_THHL (7 << 0)
#define ALS_INT_DISABLE (0 << 3)
#define ALS_INT_ENABLE (1 << 3)
#define INT_CTRL_PS_OR_LS (0 << 7)
#define INT_CTRL_PS_AND_LS (1 << 7)
/* FLAG 0x10 */
#define STK_FLAG_NF (1 << 0)
#define STK_FLAG_INPS_INT (1 << 1)
#define STK_FLAG_ALS_STATE (1 << 2)
#define STK_FLAG_PS_INT (1 << 4)
#define STK_FLAG_ALS_INT (1 << 5)
#define STK_FLAG_PSDR (1 << 6)
#define STK_FLAG_ALSDR (1 << 7)
static int ps_threshold_low;
static int ps_threshold_high;
static int val_flag;
static int sensor_active(struct i2c_client *client, int enable, int rate)
{
struct sensor_private_data *sensor =
(struct sensor_private_data *)i2c_get_clientdata(client);
int result = 0;
int status = 0;
sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg);
if (!enable) {
status = ~PS_ENABLE;
sensor->ops->ctrl_data &= status;
} else {
status = PS_ENABLE;
sensor->ops->ctrl_data |= status;
}
dev_dbg(&client->dev, "reg=0x%x, reg_ctrl=0x%x, enable=%d\n",
sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable);
result = sensor_write_reg(client, sensor->ops->ctrl_reg,
sensor->ops->ctrl_data);
if (result)
dev_err(&client->dev, "%s:fail to active sensor\n", __func__);
return result;
}
static int sensor_init(struct i2c_client *client)
{
struct sensor_private_data *sensor =
(struct sensor_private_data *)i2c_get_clientdata(client);
struct device_node *np = client->dev.of_node;
int ps_val = 0;
int result = 0;
int val = 0;
result = sensor->ops->active(client, 0, 0);
if (result) {
dev_err(&client->dev, "%s:sensor active fail\n", __func__);
return result;
}
sensor->status_cur = SENSOR_OFF;
result = of_property_read_u32(np, "ps_threshold_low", &ps_val);
if (result)
dev_err(&client->dev, "%s:Unable to read ps_threshold_low\n",
__func__);
ps_threshold_low = ps_val;
result = sensor_write_reg(client, THDL1_PS,
(unsigned char)(ps_val >> 8));
if (result) {
dev_err(&client->dev, "%s:write THDL1_PS fail\n", __func__);
return result;
}
result = sensor_write_reg(client, THDL2_PS, (unsigned char)ps_val);
if (result) {
dev_err(&client->dev, "%s:write THDL1_PS fail\n", __func__);
return result;
}
result = of_property_read_u32(np, "ps_threshold_high", &ps_val);
if (result)
dev_err(&client->dev, "%s:Unable to read ps_threshold_high\n",
__func__);
ps_threshold_high = ps_val;
result = sensor_write_reg(client, THDH1_PS,
(unsigned char)(ps_val >> 8));
if (result) {
dev_err(&client->dev, "%s:write THDH1_PS fail\n", __func__);
return result;
}
result = sensor_write_reg(client, THDH2_PS, (unsigned char)ps_val);
if (result) {
dev_err(&client->dev, "%s:write THDH1_PS fail\n", __func__);
return result;
}
result = of_property_read_u32(np, "ps_ctrl_gain", &ps_val);
if (result)
dev_err(&client->dev, "%s:Unable to read ps_ctrl_gain\n",
__func__);
result = sensor_write_reg(client, PS_CTRL,
(unsigned char)((ps_val << 4) | PS_IT_384US));
if (result) {
dev_err(&client->dev, "%s:write PS_CTRL fail\n", __func__);
return result;
}
result = of_property_read_u32(np, "ps_led_current", &ps_val);
if (result)
dev_err(&client->dev, "%s:Unable to read ps_led_current\n",
__func__);
result = sensor_write_reg(client, LED_CTRL,
(unsigned char)((ps_val << 5) | LED_CTIR_EN));
if (result) {
dev_err(&client->dev, "%s:write LED_CTRL fail\n", __func__);
return result;
}
val = sensor_read_reg(client, INT_CTRL1);
val &= ~INT_CTRL_PS_AND_LS;
if (sensor->pdata->irq_enable)
val |= PS_INT_ENABLE_FLGNFL;
else
val &= PS_INT_DISABLE;
result = sensor_write_reg(client, INT_CTRL1, val);
if (result) {
dev_err(&client->dev, "%s:write INT_CTRL fail\n", __func__);
return result;
}
return result;
}
static int stk3332_get_ps_value(int ps)
{
int index = 0;
if ((ps > ps_threshold_high) && (val_flag == 0)) {
index = 1;
val_flag = 1;
} else if ((ps < ps_threshold_low) && (val_flag == 1)) {
index = 0;
val_flag = 0;
} else {
index = -1;
}
return index;
}
static int sensor_report_value(struct i2c_client *client)
{
struct sensor_private_data *sensor =
(struct sensor_private_data *)i2c_get_clientdata(client);
int result = 0;
int value = 0;
char buffer[2] = { 0 };
int index = 1;
if (sensor->ops->read_len < 2) {
dev_err(&client->dev, "%s:length is error, len=%d\n", __func__,
sensor->ops->read_len);
return -EINVAL;
}
buffer[0] = sensor->ops->read_reg;
result = sensor_rx_data(client, buffer, sensor->ops->read_len);
if (result) {
dev_err(&client->dev, "%s:sensor read data fail\n", __func__);
return result;
}
value = (buffer[0] << 8) | buffer[1];
if (sensor->pdata->irq_enable && sensor->ops->int_status_reg) {
value = sensor_read_reg(client, sensor->ops->int_status_reg);
if (value & STK_FLAG_NF)
index = 0;
else
index = 1;
input_report_abs(sensor->input_dev, ABS_DISTANCE, index);
input_sync(sensor->input_dev);
value &= ~STK_FLAG_PS_INT;
result = sensor_write_reg(client,
sensor->ops->int_status_reg,
value);
dev_dbg(&client->dev, "%s object near = %d", sensor->ops->name, index);
if (result) {
dev_err(&client->dev, "write status reg error\n");
return result;
}
} else if (!sensor->pdata->irq_enable) {
index = stk3332_get_ps_value(value);
if (index >= 0) {
input_report_abs(sensor->input_dev, ABS_DISTANCE, index);
input_sync(sensor->input_dev);
dev_dbg(&client->dev, "%s sensor closed=%d\n",
sensor->ops->name, index);
}
}
return result;
}
static struct sensor_operate psensor_stk3332_ops = {
.name = "ps_stk3332",
.type = SENSOR_TYPE_PROXIMITY,
.id_i2c = PROXIMITY_ID_STK3332,
.read_reg = DATA1_PS,
.read_len = 2,
.id_reg = SENSOR_UNKNOW_DATA,
.id_data = SENSOR_UNKNOW_DATA,
.precision = 16,
.ctrl_reg = STK_STATE,
.int_status_reg = STK_FLAG,
.range = { 100, 65535 },
.brightness = { 10, 255 },
.trig = IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
.active = sensor_active,
.init = sensor_init,
.report = sensor_report_value,
};
static struct sensor_operate *proximity_get_ops(void)
{
return &psensor_stk3332_ops;
}
static int __init proximity_stk3332_init(void)
{
struct sensor_operate *ops = proximity_get_ops();
int result = 0;
int type = ops->type;
result = sensor_register_slave(type, NULL, NULL, proximity_get_ops);
return result;
}
static void __exit proximity_stk3332_exit(void)
{
struct sensor_operate *ops = proximity_get_ops();
int type = ops->type;
sensor_unregister_slave(type, NULL, NULL, proximity_get_ops);
}
// static int proximity_stk3332_probe(struct i2c_client *client,
// const struct i2c_device_id *devid)
// {
// return sensor_register_device(client, NULL, devid, &psensor_stk3332_ops);
// }
// static int proximity_stk3332_remove(struct i2c_client *client)
// {
// return sensor_unregister_device(client, NULL, &psensor_stk3332_ops);
// }
// static const struct i2c_device_id proximity_stk3332_id[] = {
// { "ps_stk3332", PROXIMITY_ID_STK3332 },
// {}
// };
// static struct i2c_driver proximity_stk3332_driver = {
// .probe = proximity_stk3332_probe,
// .remove = proximity_stk3332_remove,
// .shutdown = sensor_shutdown,
// .id_table = proximity_stk3332_id,
// .driver = {
// .name = "proximity_stk3332",
// #ifdef CONFIG_PM
// .pm = &sensor_pm_ops,
// #endif
// },
// };
// module_i2c_driver(proximity_stk3332_driver);
module_init(proximity_stk3332_init);
module_exit(proximity_stk3332_exit);
MODULE_AUTHOR("Kay Guo<yangbin@rock-chips.com>");
MODULE_DESCRIPTION("stk3332 proximity driver");
MODULE_LICENSE("GPL");
代码一般kernel中会有,或者客户提供,实在需要自己写的可以参考kernel中类似的产品来写。有时候不同的内核版本驱动也会有些差异。
需要配置make或Kconfig的可以加进去,然后在产品的默认config文件中选择将驱动编译成模块或build-in内核。这样整个驱动过程就差不多完成了。重新编译kernel,烧录。
正常加载驱动的log:
写个简单的应用来测试一下:
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include "linux/input.h"
#include "linux/ioctl.h"
#include <linux/types.h>
#define LS_INPUT_EVENT "/dev/input/event2"
#define LS_DEVICE_NAME "/dev/lightsensor"
#define ABS_MISC 0x28
#define EVENT_TYPE_LIGHT ABS_MISC
#define LIGHTSENSOR_IOCTL_MAGIC 'l'
#define LIGHTSENSOR_IOCTL_GET_ENABLED _IOR(LIGHTSENSOR_IOCTL_MAGIC, 1, int *)
#define LIGHTSENSOR_IOCTL_ENABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, int *)
#define LIGHTSENSOR_IOCTL_SET_RATE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 3, short)
#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo)
float indexToValue(size_t index)
{
static const float luxValues[8] = {
10.0, 160.0, 225.0, 320.0,
640.0, 1280.0, 2600.0, 10240.0
};
const size_t maxIndex = sizeof(luxValues)/sizeof(*luxValues) - 1;
if (index > maxIndex)
index = maxIndex;
return luxValues[index];
}
int get_light(void)
{
int fd;
int err = 0;
float light;
struct input_absinfo absinfo;
fd = open(LS_INPUT_EVENT, O_RDWR);
if (fd < 0) {
printf("Can't open file %s\r\n", LS_INPUT_EVENT);
return -1;
}
err = ioctl(fd, EVIOCGABS(EVENT_TYPE_LIGHT), &absinfo);
if(err<0){
printf("Error lightsensor event on\r\n");
}else{
light = indexToValue(absinfo.value);
printf("lightsensor value:%.1f\r\n",light);
}
return err;
}
int fun_lightsensor(int on)
{
int fd;
int err = 0;
int flags=on ? 1 : 0;
fd = open(LS_DEVICE_NAME, O_RDWR);
if (fd < 0) {
printf("Can't open file %s\r\n", LS_DEVICE_NAME);
return -1;
}
err = ioctl(fd, LIGHTSENSOR_IOCTL_ENABLE, &flags);
if(err<0){
printf("Error enable lightsensor\r\n");
goto error;
}
return 0;
error:
close(fd);
return err;
}
int main(int argc, char *argv[])
{
int i;
if(fun_lightsensor(1)<0){
printf("Error enable lightsensor\r\n");
}else{
for(i=0;i<20;i++){
get_light();
sleep(2);
}
fun_lightsensor(0);
}
}
在板子上运行;
至此,驱动调试完成。后续会和应用开发来沟通如何调用的问题。