| /* |
| * drivers/input/misc/ambarella_ir_philips.c |
| * |
| * History: |
| * 2007/03/28 - [Dragon Chiang] created file |
| * 2009/03/10 - [Anthony Ginger] Port to 2.6.28 |
| * |
| * Copyright (C) 2004-2009, Ambarella, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| */ |
| |
| #include <linux/platform_device.h> |
| #include <linux/interrupt.h> |
| |
| #include <plat/ambinput.h> |
| |
| /** |
| * Shift-Coded Signals (RC-5)vary the order of pulse space to code the |
| * information. In this case if the space width is short (approximately 550us) |
| * and the pulse width is long (approximately 1100us) the signal corresponds to |
| * a logical one or a high. If the space is long and the pulse is short the |
| * signal corresponds to a logical zero or a low. |
| * |
| * | | | |
| * +--| +--|--+ | +--- |
| * | | | | | | | |
| * ---+ |--+ | +--|--+ |
| * 1 | 1 | 0 | 1 |
| */ |
| |
| /* Philips (RC-5) */ |
| #define PHILIPS_DEFAULT_FREQUENCY 36000 /* 36KHz */ |
| #define PHILIPS_DEFAULT_SMALLER_TIME 1728 /* T, 1728 microseconds. */ |
| |
| /** | | | | | | | | | | | | | | | |
| * ---+-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +--- |
| * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
| * | +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ |
| * | | | | | | | | | | | | | | | |
| * | AGC |TOG|< address >|< command >| |
| * |
| * | | |
| */ |
| #define PHILIPS_LEADER_UPBOUND 0xffff /* default don't care */ |
| #define PHILIPS_LEADER_LOWBOUND 30 |
| |
| #define PHILIPS_SHC_SIG_CYC_UPBOUND 14 /* default 10~ 12 */ |
| #define PHILIPS_SHC_SIG_CYC_LOWBOUND 8 |
| |
| #define PHILIPS_SHC_DOB_CYC_UPBOUND 25 /* default 12~ 23 */ |
| #define PHILIPS_SHC_DOB_CYC_LOWBOUND 20 |
| |
| static int ambarella_ir_philips_shift_leader_code(struct ambarella_ir_info *pinfo) |
| { |
| /** | | | |
| * ---|--------+ +--------+ | |
| * | | | | | |
| * | +--------+ +--------|--- |
| * | | | |
| * | AGC | |
| * |
| * Leader | Leader | Leader | |
| */ |
| u16 val_1, val_0 = ambarella_ir_read_data(pinfo, pinfo->ir_pread); |
| |
| #if 0 |
| if ((val_0 <= PHILIPS_LEADER_UPBOUND) && |
| (val_0 > PHILIPS_LEADER_LOWBOUND)) { |
| #else |
| if (val_0 > PHILIPS_LEADER_LOWBOUND) { |
| #endif |
| } else { |
| return 0; |
| } |
| |
| if ((pinfo->ir_pread + 1) >= MAX_IR_BUFFER) { |
| val_0 = ambarella_ir_read_data(pinfo, 0); |
| val_1 = ambarella_ir_read_data(pinfo, 1); |
| } else if ((pinfo->ir_pread + 2) == MAX_IR_BUFFER) { |
| val_0 = ambarella_ir_read_data(pinfo, pinfo->ir_pread + 1); |
| val_1 = ambarella_ir_read_data(pinfo, 0); |
| } else { |
| val_0 = ambarella_ir_read_data(pinfo, pinfo->ir_pread + 1); |
| val_1 = ambarella_ir_read_data(pinfo, pinfo->ir_pread + 2); |
| } |
| |
| if ((val_0 < PHILIPS_SHC_SIG_CYC_UPBOUND) && |
| (val_0 > PHILIPS_SHC_SIG_CYC_LOWBOUND) && |
| (val_1 < PHILIPS_SHC_SIG_CYC_UPBOUND) && |
| (val_1 > PHILIPS_SHC_SIG_CYC_LOWBOUND)) |
| return 1; |
| else |
| return 0; |
| } |
| |
| static int ambarella_ir_philips_find_head(struct ambarella_ir_info *pinfo) |
| { |
| int i, val = 0; |
| |
| i = ambarella_ir_get_tick_size(pinfo) - pinfo->frame_info.frame_head_size + 1; |
| |
| while(i--) { |
| if(ambarella_ir_philips_shift_leader_code(pinfo)) { |
| dev_dbg(&pinfo->pinput_dev->dev, "find leader code, i [%d]\n", i); |
| val = 1; |
| break; |
| } else { |
| dev_dbg(&pinfo->pinput_dev->dev, "didn't find leader code, i [%d]\n", i); |
| ambarella_ir_move_read_ptr(pinfo, 1); |
| } |
| } |
| |
| return val ; |
| } |
| |
| static int ambarella_ir_philips_shift_invert_code(struct ambarella_ir_info *pinfo) |
| { |
| u16 val = ambarella_ir_read_data(pinfo, pinfo->ir_pread); |
| |
| if ((val < PHILIPS_SHC_DOB_CYC_UPBOUND) && |
| (val > PHILIPS_SHC_DOB_CYC_LOWBOUND)) |
| return 1; |
| else |
| return 0; |
| } |
| |
| static int ambarella_ir_philips_shift_repeat_code(struct ambarella_ir_info *pinfo) |
| { |
| u16 val = ambarella_ir_read_data(pinfo, pinfo->ir_pread); |
| |
| if ((val < PHILIPS_SHC_SIG_CYC_UPBOUND) && |
| (val > PHILIPS_SHC_SIG_CYC_LOWBOUND)) { |
| ambarella_ir_inc_read_ptr(pinfo); |
| |
| val = ambarella_ir_read_data(pinfo, pinfo->ir_pread); |
| if ((val < PHILIPS_SHC_SIG_CYC_UPBOUND) && |
| (val > PHILIPS_SHC_SIG_CYC_LOWBOUND)) |
| return 1; |
| else |
| return 0; |
| } else |
| return 0; |
| } |
| |
| static int ambarella_ir_philips_shift_decode(struct ambarella_ir_info *pinfo, u32 *uid) |
| { |
| int i, val = 0; |
| u8 addr = 0, data = 0; |
| |
| ambarella_ir_move_read_ptr(pinfo, 3); |
| |
| /* Get toggle code and Initialize start value */ |
| if (ambarella_ir_philips_shift_invert_code(pinfo)) |
| val = 1; |
| else if (ambarella_ir_philips_shift_repeat_code(pinfo)) |
| val = 0; |
| else { |
| dev_dbg(&pinfo->pinput_dev->dev, "Err->toggle code doesn't match"); |
| return (-1); |
| } |
| |
| dev_dbg(&pinfo->pinput_dev->dev, "toggle code:%d", val); |
| |
| /* address */ |
| for (i = 0; i < 5; i++) { |
| if (ambarella_ir_philips_shift_invert_code(pinfo)) { |
| val = 1 - val; |
| } else if (ambarella_ir_philips_shift_repeat_code(pinfo)) { |
| }else { |
| dev_dbg(&pinfo->pinput_dev->dev, "Err->addr code(%d) doesn't match", i); |
| return (-1); |
| } |
| addr = (addr << 1) | val; |
| ambarella_ir_inc_read_ptr(pinfo); |
| } |
| |
| /* data */ |
| for (i = 0; i < 6; i++) { |
| if (ambarella_ir_philips_shift_invert_code(pinfo)) { |
| val = 1 - val; |
| } else if (ambarella_ir_philips_shift_repeat_code(pinfo)) { |
| }else { |
| dev_dbg(&pinfo->pinput_dev->dev, "Err->data code(%d) doesn't match", i); |
| return (-1); |
| } |
| data = (data << 1) | val; |
| ambarella_ir_inc_read_ptr(pinfo); |
| } |
| |
| *uid = (addr << 16) | data; |
| |
| return 0; |
| } |
| |
| int ambarella_ir_philips_parse(struct ambarella_ir_info *pinfo, u32 *uid) |
| { |
| int rval; |
| int cur_ptr = pinfo->ir_pread; |
| |
| if (ambarella_ir_philips_find_head(pinfo) |
| && ambarella_ir_get_tick_size(pinfo) >= pinfo->frame_info.frame_data_size |
| + pinfo->frame_info.frame_head_size) { |
| |
| dev_dbg(&pinfo->pinput_dev->dev, "go to decode statge\n"); |
| ambarella_ir_move_read_ptr(pinfo, pinfo->frame_info.frame_head_size);//move ptr to data |
| rval = ambarella_ir_philips_shift_decode(pinfo, uid); |
| } else { |
| return -1; |
| } |
| |
| if (rval >= 0) { |
| dev_dbg(&pinfo->pinput_dev->dev, "buffer[%d]-->mornal key\n", cur_ptr); |
| return 0; |
| } |
| |
| return (-1); |
| } |
| |
| void ambarella_ir_get_philips_info(struct ambarella_ir_frame_info *pframe_info) |
| { |
| pframe_info->frame_head_size = 6; |
| pframe_info->frame_data_size = 22; |
| pframe_info->frame_end_size = 1; |
| pframe_info->frame_repeat_head_size = 0; |
| } |
| |