RK3399 android7.1 话柄电话功能
实现功能:挂柄接IO口+GND控制话机听筒与系统喇叭的切换(抬起手柄声音由喇叭切换到听筒,挂到磁吸底座喇叭出声)
应用场景: 电子电话班牌,电话机等
硬件接线方式:
电话手柄:听筒接耳机座子<HRP,GND>,麦克风接<MIC+,MIC->
电话底座:磁吸座子接<IO2,GND>
一,IO(gpio)口为系统cpu直出
1.确认gpio引脚
例如(IO2+GND):
io2-gpio =<&gpio2 RK_PD1 GPIO_ACTIVE_HIGH>;
2.将需要对地控制的gpio引脚直接替换原生的耳机控制脚
一般dts中有描述:
rk_headset: rk-headset {
compatible = "rockchip_headset";
headset_gpio = <&gpio2 RK_PD1 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hp_det>;
};
例如(IO2+GND):
diff --git a/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi b/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi
index 65a3266d09..e6a621adce 100644
--- a/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi
+++ b/kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi
@@ -17,10 +17,9 @@
rk_headset: rk-headset {
compatible = "rockchip_headset";
- headset_gpio = <&gpio3 RK_PC2 GPIO_ACTIVE_HIGH>;
+ headset_gpio = <&gpio2 RK_PD1 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hp_det>;
- io-channels = <&saradc 2>;
};
vcc2v5_sys: vcc2v5-ddr {
@@ -415,7 +414,7 @@
};
headphone {
hp_det: hp-det {
- rockchip,pins = <3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>;
+ rockchip,pins = <2 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
二,通过xrm117x驱动 i2c转外部扩展GPIO
1.添加gpio_key.c
代码路径:kernel/drivers/char/gpio_key.c
代码功能:用于管理 GPIO 键,通过一个线程监控 GPIO 键的状态变化并相应地处理这些状态变化。
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/debugfs.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/iio/consumer.h>
#include <dt-bindings/pinctrl/rk.h>
/* Debug */
#define DEBUG 0
#if DEBUG
#define DBG_GPIO(x...) printk(x)
#else
#define DBG_GPIO(x...) do { } while (0)
#endif
#define KETDELAY 50
enum {
SMDT_KEY_F1 = 96,
SMDT_KEY_F2 = 97,
};
enum {
XRM117X_IO0 = 0,
XRM117X_IO1 = 1,
XRM117X_IO2 = 2,
XRM117X_IO3 = 3,
XRM117X_IO4 = 4,
XRM117X_IO5 = 5,
XRM117X_IO6 = 6,
XRM117X_IO7 = 7,
};
/***************************************************************************************************************************/
extern int android_flag;
static struct task_struct * gpio_key_task;
extern void smdt_hp_det(char flag);
extern void smdt_gpiokey(int event);
extern int xrm117x_gpio_sw_cfg_set(int gpio_sw_cdev, int mul_cfg , int data);
extern int xrm117x_gpio_sw_data_get(int gpio_sw_cdev);
/***************************************************************************************************************************/
int read_gpio(void)
{
static char gpio_status=1;
static unsigned int count=0;
int ret;
int event=0;
ret = xrm117x_gpio_sw_data_get(XRM117X_IO2); //控制脚为IO2,可根据需求自行切换
if(ret < 0)
return -1;
DBG_GPIO("gpio1=%d\n",ret);
if(ret == gpio_status)
{
count++;
}
else
{
gpio_status = ret;
count = 0;
}
if(count == 3)
{
smdt_hp_det(gpio_status);
DBG_GPIO("send event=%d\n",event);
}
}
int gpio_key_run_thread(void *parg)
{
msleep(15000);
while(!android_flag)
msleep(1000);
printk("%s in\n",__func__);
xrm117x_gpio_sw_cfg_set(XRM117X_IO2, 0, 0); //控制脚为IO2,可根据需求自行切换
while(1)
{
msleep(KETDELAY);
read_gpio();
}
return 0;
}
static int gpio_key_probe(struct platform_device *pdev)
{
int ret;
printk("%s in\n",__func__);
gpio_key_task = kthread_create(gpio_key_run_thread, (void*)0, "gpio_key proc");
if(IS_ERR(gpio_key_task))
{
printk(KERN_ERR "### [fy]:gpio_key_task Unable to start kernel thread %s.\n","gpio_key proc");
gpio_key_task = NULL;
}
if(gpio_key_task)
wake_up_process(gpio_key_task);
printk("%s ok\n",__func__);
return 0;
}
/***************************************************************************************************************************/
static const struct of_device_id gpio_key_of_match[] = {
{ .compatible = "rockchip,rk3399-gpio-key", },
{},
};
MODULE_DEVICE_TABLE(of, gpio_key_of_match);
static struct platform_driver gpio_key_driver = {
.probe = gpio_key_probe,
.driver = {
.name = "rk3399-gpio-key",
.owner = THIS_MODULE,
.of_match_table = gpio_key_of_match,
},
};
module_platform_driver_probe(gpio_key_driver, gpio_key_probe);
MODULE_LICENSE("GPL");
2.Makefile 中添加gpio_key.o;
代码路径:kernel/drivers/char/Makefile
obj-y += gpio_key.o
3.xrm117x驱动中添加 对现有 GPIO 配置和数据检索函数包装;
代码路径:kernel/drivers/tty/serial/xrm117x.c
diff --git a/kernel/drivers/tty/serial/xrm117x.c b/kernel/drivers/tty/serial/xrm117x.c
index d65df1f7c1..0b85f1fe90 100644
--- a/kernel/drivers/tty/serial/xrm117x.c
+++ b/kernel/drivers/tty/serial/xrm117x.c
@@ -1634,6 +1634,18 @@ static int gpio_sw_data_get(int gpio_sw_cdev)
return xrm117x_gpio_get(smdt,gpio_sw_cdev);
}
+int xrm117x_gpio_sw_cfg_set(int gpio_sw_cdev, int mul_cfg , int data)
+{
+ return gpio_sw_cfg_set(gpio_sw_cdev, mul_cfg , data);
+}
+EXPORT_SYMBOL(xrm117x_gpio_sw_cfg_set);
+
+int xrm117x_gpio_sw_data_get(int gpio_sw_cdev)
+{
+ return gpio_sw_data_get(gpio_sw_cdev);
+}
+EXPORT_SYMBOL(xrm117x_gpio_sw_data_get);
+
static int gpio_sw_drv_get(int gpio_sw_cdev)
{
int ret;
4.由于音频芯片使用的是es8388,需要到对应驱动中 处理耳机插入检测的中断;
代码路径:kernel/sound/soc/codecs/es8388.c
diff --git a/kernel/sound/soc/codecs/es8388.c b/kernel/sound/soc/codecs/es8388.c
index dc4726bb1b..5079ecf507 100644
--- a/kernel/sound/soc/codecs/es8388.c
+++ b/kernel/sound/soc/codecs/es8388.c
@@ -123,8 +123,22 @@ static int es8388_set_gpio(int gpio, bool level)
return 0;
}
+void smdt_hp_det(char flag)
+{
+ struct es8388_priv *es8388 = es8388_private;
+
+ if (flag != es8388->hp_det_level) //根据检测到的级别更新耳机插入状态
+ es8388->hp_inserted = 0;
+ else
+ es8388->hp_inserted = 1;
+ printk("--------hp_det_irq_handler hp_det_level=%d hp_inserted=%d\n",es8388->hp_det_level,es8388->hp_inserted);
+ switch_set_state(&es8388->sw_dev, es8388->hp_inserted ? head_havemic : 0);
+}
+EXPORT_SYMBOL(smdt_hp_det);
+
@@ -833,7 +848,7 @@ static int es8388_i2c_probe(struct i2c_client *i2c,
}
//fixbug:power on with headset
- headset_det_gpio_val = gpio_get_value(es8388->hp_det_gpio);
+ headset_det_gpio_val = 0;//gpio_get_value(es8388->hp_det_gpio);
if(headset_det_gpio_val == 1){
//if headset in, set h2w 1. (default is headset and ignore 3/4)
switch_set_state(&es8388->sw_dev, head_havemic);