rk平台 linux系统 光距离感应器stk3332驱动调试

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

在板子上运行;

至此,驱动调试完成。后续会和应用开发来沟通如何调用的问题。

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个示例的ls_stk3332.c驱动程序,用于实现RK3588与STK3332之间的音频输入和输出功能: ``` #include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/slab.h> #include <linux/regmap.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/control.h> #define STK3332_REG_GAIN 0x00 #define STK3332_REG_VOLUME 0x01 #define STK3332_REG_MUTE 0x02 struct stk3332_data { struct regmap *regmap; unsigned int gain; unsigned int volume; bool mute; }; static int stk3332_set_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct stk3332_data *data = snd_kcontrol_chip(kcontrol); unsigned int gain = ucontrol->value.integer.value[0]; if (gain > 255) gain = 255; data->gain = gain; regmap_write(data->regmap, STK3332_REG_GAIN, gain); return 0; } static int stk3332_get_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct stk3332_data *data = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = data->gain; return 0; } static int stk3332_set_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct stk3332_data *data = snd_kcontrol_chip(kcontrol); unsigned int volume = ucontrol->value.integer.value[0]; if (volume > 255) volume = 255; data->volume = volume; regmap_write(data->regmap, STK3332_REG_VOLUME, volume); return 0; } static int stk3332_get_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct stk3332_data *data = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = data->volume; return 0; } static int stk3332_set_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct stk3332_data *data = snd_kcontrol_chip(kcontrol); bool mute = ucontrol->value.integer.value[0]; data->mute = mute; regmap_write(data->regmap, STK3332_REG_MUTE, mute ? 1 : 0); return 0; } static int stk3332_get_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct stk3332_data *data = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = data->mute ? 1 : 0; return 0; } static const struct snd_kcontrol_new stk3332_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Gain", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = snd_ctl_boolean_mono_info, .get = stk3332_get_gain, .put = stk3332_set_gain, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = snd_ctl_boolean_mono_info, .get = stk3332_get_volume, .put = stk3332_set_volume, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mute", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = snd_ctl_boolean_mono_info, .get = stk3332_get_mute, .put = stk3332_set_mute, }, { } /* end */ }; static int stk3332_pcm_open(struct snd_pcm_substream *substream) { return 0; } static int stk3332_pcm_close(struct snd_pcm_substream *substream) { return 0; } static int stk3332_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { return 0; } static int stk3332_pcm_hw_free(struct snd_pcm_substream *substream) { return 0; } static struct snd_pcm_ops stk3332_pcm_ops = { .open = stk3332_pcm_open, .close = stk3332_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = stk3332_pcm_hw_params, .hw_free = stk3332_pcm_hw_free, }; static int stk3332_pcm_new(struct snd_card *card, struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm; int ret; ret = snd_pcm_new(card, "STK3332 PCM", 0, 1, 0, &pcm); if (ret < 0) return ret; pcm->private_data = rtd; pcm->info_flags = 0; strcpy(pcm->name, "STK3332 PCM"); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &stk3332_pcm_ops); return 0; } static int stk3332_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct stk3332_data *data; struct regmap *regmap; regmap = dev_get_regmap(dev->parent, NULL); if (!regmap) { dev_err(dev, "Failed to get regmap\n"); return -ENODEV; } data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; data->regmap = regmap; data->gain = 128; data->volume = 128; data->mute = false; platform_set_drvdata(pdev, data); // 注册音频控制 snd_soc_register_codec(&pdev->dev, &codec_stk3332, &stk3332_dai, 1); // 注册PCM设备 return snd_soc_new_pcm_runtime(&pdev->dev, &stk3332_pcm_dai, &stk3332_pcm_platform, 0); } static int stk3332_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; } static const struct of_device_id stk3332_of_match[] = { { .compatible = "st,stk3332", }, { }, }; MODULE_DEVICE_TABLE(of, stk3332_of_match); static struct platform_driver stk3332_driver = { .probe = stk3332_probe, .remove = stk3332_remove, .driver = { .name = "stk3332", .of_match_table = stk3332_of_match, }, }; module_platform_driver(stk3332_driver); MODULE_DESCRIPTION("STK3332 audio driver"); MODULE_AUTHOR("Your Name"); MODULE_LICENSE("GPL"); ``` 以上驱动程序仅供参考,具体的驱动程序要根据实际的硬件连接和用需求进行调整和修改。同时,需要根据实际情况进行dts配置和驱动程序的加载,以实现音频输入和输出的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值