/* switch data register*/
struct lc1120_priv *data = container_of(codec, struct lc1120_priv, codec); //从元素codec,得到lc1120_priv地址
data->sdev.name = "h2w"; //switch设备只需要给个名字就能注册了。
ret = switch_dev_register(&data->sdev); //注册switch设备
if(ret < 0){
printk("lc1120 switch register failed\n");
goto switch_exit;
}
lc1120_switch_init(codec); //switch设备初始化,即根据启动情况设置state初始值
state = lc1120_comp_state_get(codec, COMP_JACK); //根据寄存器状况,获得state状态
switch_set_state(&data->sdev, state); //把寄存器读出来的状态写入sys/下的 state
lc1120_comp_state_clear(&data->codec); //清除寄存器状态
/* irq */
INIT_WORK(&data->irq_work, lc1120_irq_work_handler); //初始化一个中断处理程序
struct i2c_client * client = (struct i2c_client *)(codec->control_data); //得到client
ret = gpio_request(client->irq, "lc1120"); //得到client中的irq号,就是board_i2c_info中的i2c设备irq
if(ret < 0){
printk(KERN_ERR "lc1120 request GPIO error!!\n");
return ret;
}
ret = gpio_direction_input(client->irq); //把连接irq中断信号的GPIO 设成输入模式
if(ret < 0){
printk(KERN_ERR "LC1120: Failed to request GPIO.\n");
goto gpio_exit;
}
client->irq = gpio_to_irq(client->irq); //双核时,把该GPIO映射到另一个cpu的中断控制器
//注册一个中断,中断号为client->irq
//中断处理函数为lc1120_irq_handle
//中断触发模式IRQF_TRIGGER_RISING
ret = request_irq(client->irq, lc1120_irq_handle, IRQF_TRIGGER_RISING,
"lc1120_IRQ", data);
if(ret < 0){
printk(KERN_ERR "LC1120 i2c probe : request irq failed!\n");
goto gpio_exit;
}
/* register input for headset button*/
data->input = input_allocate_device(); //申请一个input设备的内存。
if (!data->input) {
ret = -ENOMEM;
goto input_free;
}
data->input->name = "HS button"; //input设备初始化
__set_bit(EV_KEY, data->input->evbit);
__set_bit(KEY_MEDIA, data->input->keybit);
__set_bit(KEY_END, data->input->keybit);
ret = input_register_device(data->input); //注册一个input设备。
if (ret < 0)
goto input_unregister;
return ret;
input_unregister:
input_unregister_device(data->input);
input_free:
input_free_device(data->input);
gpio_exit:
gpio_free(client->irq);
switch_exit:
switch_dev_unregister(&data->sdev);
pcm_err:
return ret;
}
static int lc1120_switch_init(codec){ //switch功能寄存器初始化
int r85, r84, r94;
D_ENTER;
/* JACK detect init */
r85 = lc1120_read(codec, LC1120_R85);
r85 |= (1 << LC1120_BIT_JACK_DET_EN);
r85 &= ~(1 << LC1120_BIT_JACK_DET_POL);
lc1120_write(codec, LC1120_R85, r85);
/* hookswitch init*/
r84 = lc1120_read(codec, LC1120_R84);
r84 |= (1 << LC1120_BIT_HS_DET_EN);
lc1120_write(codec, LC1120_R84, r84);
/* disable ALC irq*/
r94 = lc1120_read(codec, LC1120_R94);
r94 |= (1 << LC1120_CD_ENB_ALC);
lc1120_write(codec, LC1120_R94, r94);
return 0;
}
static int lc1120_comp_state_get(struct snd_soc_codec *codec, int id) //获取jack detect和Hookswitch寄存器状况
{
D_ENTER;
int r100, r101;
int state, bit;
r100 = lc1120_read(codec, LC1120_R100);
switch (id){
case COMP_JACK:
bit = LC1120_BIT_COMP_JACK;
break;
case COMP_HS:
bit = LC1120_BIT_COMP_HS;
break;
default:
printk(KERN_INFO "comp id mismatch");
return 0;
}
state = (r100 & (1 << bit)) ? 1 : 0;
return state;
}
static int lc1120_comp_state_clear(struct snd_soc_codec *codec){ //清除寄存器状态
D_ENTER;
int r9 = 0x0f;
lc1120_write(codec, LC1120_R9, r9);
r9 = 0;
lc1120_write(codec, LC1120_R9, r9);
return 0;
}
static irqreturn_t lc1120_irq_handle(int irq, void *dev_id){ //中断处理程序
struct lc1120_priv *data = (struct lc1120_priv *)dev_id;
D_ENTER;
schedule_work(&data->irq_work); //里面schedule_work()创建了一个工作队列
return IRQ_HANDLED;
}
static void lc1120_irq_work_handler(struct work_struct *work) //工作队列的中断处理程序
{
int state;
struct lc1120_priv *data = container_of(work, struct lc1120_priv, irq_work);
D_ENTER;
state = lc1120_comp_state_get(&data->codec, COMP_JACK); //获得寄存器状态
switch_set_state(&data->sdev, state); //再把寄存器状态写入sys/下的state
#if 0
state = lc1120_comp_state_get(&data->codec, COMP_HS);
if (state){
data->button_time = jiffies;
}else {
if (time_after(jiffies, data->button_time + COMIP_SWITCH_BUTTON_LONG_TIME)) {
printk("Hook long pressed.\n");
input_report_key(data->input, KEY_END, 1);
input_report_key(data->input, KEY_END, 0);
} else {
printk("Hook pressed.\n");
input_report_key(data->input, KEY_MEDIA, 1);
input_report_key(data->input, KEY_MEDIA, 0);
}
input_sync(data->input);
}
#endif
lc1120_comp_state_clear(&data->codec);
}