static int pmic8058_kpd_init(struct pmic8058_kp *kp) { int bits, rc, cycles; u8 scan_val = 0, ctrl_val = 0; static u8 row_bits[] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, }; /* Find column bits */ if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN) bits = 0; else bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN; ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) << KEYP_CTRL_SCAN_COLS_SHIFT; /* Find row bits */ if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN) bits = 0; else if (kp->pdata->num_rows > MATRIX_MAX_ROWS) bits = KEYP_CTRL_SCAN_ROWS_BITS; else bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN]; /* Use max rows to fix last row problem if actual rows are less */ if (kp->flags & KEYF_FIX_LAST_ROW) bits = KEYP_CTRL_SCAN_ROWS_BITS; ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT); rc = pmic8058_kp_write_u8(kp, ctrl_val, KEYP_CTRL); if (rev == PMIC8058_REV_A0) bits = fls(kp->pdata->debounce_ms) - 1; else bits = kp->pdata->debounce_ms / 5; scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT); bits = fls(kp->pdata->scan_delay_ms) - 1; scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT); /* Row hold time is a multiple of 32KHz cycles. */ cycles = kp->pdata->row_hold_us * KEYP_CLOCK_FREQ / USEC_PER_SEC; bits = 3; /* Max : b11 */ while (bits) { if (cycles >= (2 << bits)) break; bits--; } scan_val |= (bits << KEYP_SCAN_ROW_HOLD_SHIFT); rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN); return rc; }
/* * NOTE: Last row multi-interrupt issue * * In PMIC Rev A0, if any key in the last row of the keypad matrix * is pressed and held, the H/W keeps on generating interrupts. * Software work-arounds it by programming the keypad controller next level * up rows (for 8x12 matrix it is 15 rows) so the keypad controller * thinks of more-rows than the actual ones, so the actual last-row * in the matrix won't generate multiple interrupts. */ static int pmic8058_kpd_init(struct pmic8058_kp *kp) { int bits, rc, cycles; u8 scan_val = 0, ctrl_val = 0; static u8 row_bits[] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, }; /* Find column bits */ if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN) bits = 0; else bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN; ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) << KEYP_CTRL_SCAN_COLS_SHIFT; /* Find row bits */ if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN) bits = 0; else if (kp->pdata->num_rows > PM8058_MAX_ROWS) bits = KEYP_CTRL_SCAN_ROWS_BITS; else bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN]; /* Use max rows to fix last row problem if actual rows are less */ if (kp->flags & KEYF_FIX_LAST_ROW && (kp->pdata->num_rows != PM8058_MAX_ROWS)) bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN + 1]; ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT); rc = pmic8058_kp_write_u8(kp, ctrl_val, KEYP_CTRL); if (pm8058_rev(kp->pm_chip) == PM_8058_REV_1p0) bits = fls(kp->pdata->debounce_ms[0]) - 1; else bits = (kp->pdata->debounce_ms[1] / 5) - 1; scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT); bits = fls(kp->pdata->scan_delay_ms) - 1; scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT); /* Row hold time is a multiple of 32KHz cycles. */ cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC; scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT); rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN); return rc; }
static int pmic8058_kpd_init(struct pmic8058_kp *kp) { int bits, rc, cycles; u8 scan_val = 0, ctrl_val = 0; static u8 row_bits[] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, }; if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN) bits = 0; else bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN; ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) << KEYP_CTRL_SCAN_COLS_SHIFT; if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN) bits = 0; else if (kp->pdata->num_rows > MATRIX_MAX_ROWS) bits = KEYP_CTRL_SCAN_ROWS_BITS; else bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN]; if (kp->flags & KEYF_FIX_LAST_ROW && (kp->pdata->num_rows != MATRIX_MAX_ROWS)) bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN + 1]; ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT); rc = pmic8058_kp_write_u8(kp, ctrl_val, KEYP_CTRL); if (pm8058_rev(kp->pm_chip) == PM_8058_REV_1p0) bits = fls(kp->pdata->debounce_ms[0]) - 1; else bits = (kp->pdata->debounce_ms[1] / 5) - 1; scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT); bits = fls(kp->pdata->scan_delay_ms) - 1; scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT); cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC; scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT); rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN); return rc; }
static void pmic8058_kp_disable(struct pmic8058_kp *kp) { if (kp->disable_depth++ == 0) { disable_irq(kp->key_sense_irq); disable_irq(kp->key_stuck_irq); kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN; pmic8058_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL); } }
static void pmic8058_kp_enable(struct pmic8058_kp *kp) { if (!pmic8058_kp_disabled(kp)) return; if (--kp->disable_depth == 0) { kp->ctrl_reg |= KEYP_CTRL_KEYP_EN; pmic8058_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL); enable_irq(kp->key_sense_irq); enable_irq(kp->key_stuck_irq); } }
/* * Synchronous read protocol for RevB0 onwards: * * 1. Write '1' to ReadState bit in KEYP_SCAN register * 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode * synchronously * 3. Read rows in old array first if events are more than one * 4. Read rows in recent array * 5. Wait 4*32KHz clocks * 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can * synchronously exit read mode. */ static int pmic8058_chk_sync_read(struct pmic8058_kp *kp) { int rc; u8 scan_val; rc = pmic8058_kp_read_u8(kp, &scan_val, KEYP_SCAN); scan_val |= 0x1; rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN); /* 2 * 32KHz clocks */ udelay((2 * USEC_PER_SEC / KEYP_CLOCK_FREQ) + 1); return rc; }
static int pmic8058_kp_read_matrix(struct pmic8058_kp *kp, u16 *new_state, u16 *old_state) { int rc, read_rows; u8 scan_val; static u8 rows[] = { 5, 6, 7, 8, 10, 10, 12, 12, 15, 15, 15, 18, 18, 18 }; if (kp->flags & KEYF_FIX_LAST_ROW && (kp->pdata->num_rows != PM8058_MAX_ROWS)) read_rows = rows[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN + 1]; #if 1 //Qualcomm patch for keypad matrix 2*5 else if (kp->pdata->num_rows < PM8058_MIN_ROWS) read_rows = PM8058_MIN_ROWS; #endif else read_rows = kp->pdata->num_rows; if (pm8058_rev(kp->pm_chip) > PM_8058_REV_1p0) pmic8058_chk_sync_read(kp); if (old_state) rc = pmic8058_kp_read_data(kp, old_state, KEYP_OLD_DATA, read_rows); rc = pmic8058_kp_read_data(kp, new_state, KEYP_RECENT_DATA, read_rows); if (pm8058_rev(kp->pm_chip) > PM_8058_REV_1p0) { /* 4 * 32KHz clocks */ udelay((4 * USEC_PER_SEC / KEYP_CLOCK_FREQ) + 1); rc = pmic8058_kp_read(kp, &scan_val, KEYP_SCAN, 1); scan_val &= 0xFE; rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN); } return rc; }
static int pm8058_kp_config_drv(int gpio_start, int num_gpios) { int rc; struct pm8058_gpio kypd_drv = { .direction = PM_GPIO_DIR_OUT, .output_buffer = PM_GPIO_OUT_BUF_OPEN_DRAIN, .output_value = 0, .pull = PM_GPIO_PULL_NO, .vin_sel = 2, .out_strength = PM_GPIO_STRENGTH_LOW, .function = PM_GPIO_FUNC_1, .inv_int_pol = 1, }; if (gpio_start < 0 || num_gpios < 0 || num_gpios > PM8058_GPIOS) return -EINVAL; while (num_gpios--) { rc = pm8058_gpio_config(gpio_start++, &kypd_drv); if (rc) { pr_err("%s: FAIL pm8058_gpio_config(): rc=%d.\n", __func__, rc); return rc; } } return 0; } static int pm8058_kp_config_sns(int gpio_start, int num_gpios) { int rc; struct pm8058_gpio kypd_sns = { .direction = PM_GPIO_DIR_IN, .pull = PM_GPIO_PULL_UP_31P5, .vin_sel = 2, .out_strength = PM_GPIO_STRENGTH_NO, .function = PM_GPIO_FUNC_NORMAL, .inv_int_pol = 1, }; if (gpio_start < 0 || num_gpios < 0 || num_gpios > PM8058_GPIOS) return -EINVAL; while (num_gpios--) { rc = pm8058_gpio_config(gpio_start++, &kypd_sns); if (rc) { pr_err("%s: FAIL pm8058_gpio_config(): rc=%d.\n", __func__, rc); return rc; } } return 0; } /* * keypad controller should be initialized in the following sequence * only, otherwise it might get into FSM stuck state. * * - Initialize keypad control parameters, like no. of rows, columns, * timing values etc., * - configure rows and column gpios pull up/down. * - set irq edge type. * - enable the keypad controller. */ static int __devinit pmic8058_kp_probe(struct platform_device *pdev) { struct pmic8058_keypad_data *pdata = pdev->dev.platform_data; const struct matrix_keymap_data *keymap_data; struct pmic8058_kp *kp; int rc; unsigned short *keycodes; u8 ctrl_val; struct pm8058_chip *pm_chip; pm_chip = platform_get_drvdata(pdev); if (pm_chip == NULL) { dev_err(&pdev->dev, "no parent data passed in\n"); return -EFAULT; } if (!pdata || !pdata->num_cols || !pdata->num_rows || pdata->num_cols > PM8058_MAX_COLS || pdata->num_rows > PM8058_MAX_ROWS || pdata->num_cols < PM8058_MIN_COLS #if 0 || pdata->num_rows < PM8058_MIN_ROWS #endif ) { dev_err(&pdev->dev, "invalid platform data\n"); return -EINVAL; } if (pdata->rows_gpio_start < 0 || pdata->cols_gpio_start < 0) { dev_err(&pdev->dev, "invalid gpio_start platform data\n"); return -EINVAL; } if (!pdata->scan_delay_ms || pdata->scan_delay_ms > MAX_SCAN_DELAY || pdata->scan_delay_ms < MIN_SCAN_DELAY || !is_power_of_2(pdata->scan_delay_ms)) { dev_err(&pdev->dev, "invalid keypad scan time supplied\n"); return -EINVAL; } if (!pdata->row_hold_ns || pdata->row_hold_ns > MAX_ROW_HOLD_DELAY || pdata->row_hold_ns < MIN_ROW_HOLD_DELAY || ((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) { dev_err(&pdev->dev, "invalid keypad row hold time supplied\n"); return -EINVAL; } if (pm8058_rev(pm_chip) == PM_8058_REV_1p0) { if (!pdata->debounce_ms || !is_power_of_2(pdata->debounce_ms[0]) || pdata->debounce_ms[0] > MAX_DEBOUNCE_A0_TIME || pdata->debounce_ms[0] < MIN_DEBOUNCE_A0_TIME) { dev_err(&pdev->dev, "invalid debounce time supplied\n"); return -EINVAL; } } else { if (!pdata->debounce_ms || ((pdata->debounce_ms[1] % 5) != 0) || pdata->debounce_ms[1] > MAX_DEBOUNCE_B0_TIME || pdata->debounce_ms[1] < MIN_DEBOUNCE_B0_TIME) { dev_err(&pdev->dev, "invalid debounce time supplied\n"); return -EINVAL; } } keymap_data = pdata->keymap_data; if (!keymap_data) { dev_err(&pdev->dev, "no keymap data supplied\n"); return -EINVAL; } kp = kzalloc(sizeof(*kp), GFP_KERNEL); if (!kp) return -ENOMEM; keycodes = kzalloc(PM8058_MATRIX_MAX_SIZE * sizeof(*keycodes), GFP_KERNEL); if (!keycodes) { rc = -ENOMEM; goto err_alloc_mem; } platform_set_drvdata(pdev, kp); mutex_init(&kp->mutex); kp->pdata = pdata; kp->dev = &pdev->dev; kp->keycodes = keycodes; kp->pm_chip = pm_chip; if (pm8058_rev(pm_chip) == PM_8058_REV_1p0) kp->flags |= KEYF_FIX_LAST_ROW; kp->input = input_allocate_device(); if (!kp->input) { dev_err(&pdev->dev, "unable to allocate input device\n"); rc = -ENOMEM; goto err_alloc_device; } /* Enable runtime PM ops, start in ACTIVE mode */ rc = pm_runtime_set_active(&pdev->dev); if (rc < 0) dev_dbg(&pdev->dev, "unable to set runtime pm state\n"); pm_runtime_enable(&pdev->dev); kp->key_sense_irq = platform_get_irq(pdev, 0); if (kp->key_sense_irq < 0) { dev_err(&pdev->dev, "unable to get keypad sense irq\n"); rc = -ENXIO; goto err_get_irq; } kp->key_stuck_irq = platform_get_irq(pdev, 1); if (kp->key_stuck_irq < 0) { dev_err(&pdev->dev, "unable to get keypad stuck irq\n"); rc = -ENXIO; goto err_get_irq; } if (pdata->input_name) kp->input->name = pdata->input_name; else kp->input->name = "PMIC8058 keypad"; if (pdata->input_phys_device) kp->input->phys = pdata->input_phys_device; else kp->input->phys = "pmic8058_keypad/input0"; kp->input->dev.parent = &pdev->dev; kp->input->id.bustype = BUS_HOST; kp->input->id.version = 0x0001; kp->input->id.product = 0x0001; kp->input->id.vendor = 0x0001; kp->input->evbit[0] = BIT_MASK(EV_KEY); if (pdata->rep) __set_bit(EV_REP, kp->input->evbit); kp->input->keycode = keycodes; kp->input->keycodemax = PM8058_MATRIX_MAX_SIZE; kp->input->keycodesize = sizeof(*keycodes); matrix_keypad_build_keymap(keymap_data, PM8058_ROW_SHIFT, kp->input->keycode, kp->input->keybit); input_set_capability(kp->input, EV_MSC, MSC_SCAN); input_set_drvdata(kp->input, kp); rc = input_register_device(kp->input); if (rc < 0) { dev_err(&pdev->dev, "unable to register keypad input device\n"); goto err_get_irq; } /* initialize keypad state */ memset(kp->keystate, 0xff, sizeof(kp->keystate)); memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate)); rc = pmic8058_kpd_init(kp); if (rc < 0) { dev_err(&pdev->dev, "unable to initialize keypad controller\n"); goto err_kpd_init; } rc = pm8058_kp_config_sns(pdata->cols_gpio_start, pdata->num_cols); if (rc < 0) { dev_err(&pdev->dev, "unable to configure keypad sense lines\n"); goto err_gpio_config; } rc = pm8058_kp_config_drv(pdata->rows_gpio_start, pdata->num_rows); if (rc < 0) { dev_err(&pdev->dev, "unable to configure keypad drive lines\n"); goto err_gpio_config; } rc = request_threaded_irq(kp->key_sense_irq, NULL, pmic8058_kp_irq, IRQF_TRIGGER_RISING, "pmic-keypad", kp); if (rc < 0) { dev_err(&pdev->dev, "failed to request keypad sense irq\n"); goto err_req_sense_irq; } rc = request_threaded_irq(kp->key_stuck_irq, NULL, pmic8058_kp_stuck_irq, IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp); if (rc < 0) { dev_err(&pdev->dev, "failed to request keypad stuck irq\n"); goto err_req_stuck_irq; } rc = pmic8058_kp_read_u8(kp, &ctrl_val, KEYP_CTRL); ctrl_val |= KEYP_CTRL_KEYP_EN; rc = pmic8058_kp_write_u8(kp, ctrl_val, KEYP_CTRL); kp->ctrl_reg = ctrl_val; __dump_kp_regs(kp, "probe"); rc = device_create_file(&pdev->dev, &dev_attr_key_pressed); if (rc < 0) goto err_create_file; rc = device_create_file(&pdev->dev, &dev_attr_disable_kp); if (rc < 0) goto err_create_file; device_init_wakeup(&pdev->dev, pdata->wakeup); return 0; err_create_file: free_irq(kp->key_stuck_irq, kp); err_req_stuck_irq: free_irq(kp->key_sense_irq, kp); err_req_sense_irq: err_gpio_config: err_kpd_init: input_unregister_device(kp->input); kp->input = NULL; err_get_irq: pm_runtime_set_suspended(&pdev->dev); pm_runtime_disable(&pdev->dev); input_free_device(kp->input); err_alloc_device: kfree(keycodes); err_alloc_mem: kfree(kp); return rc; } static int __devexit pmic8058_kp_remove(struct platform_device *pdev) { struct pmic8058_kp *kp = platform_get_drvdata(pdev); // sysfs_remove_group(&pdev->dev.kobj, &pmic8058_keys_attr_group); pm_runtime_set_suspended(&pdev->dev); pm_runtime_disable(&pdev->dev); device_remove_file(&pdev->dev, &dev_attr_key_pressed); device_remove_file(&pdev->dev, &dev_attr_disable_kp); device_init_wakeup(&pdev->dev, 0); free_irq(kp->key_stuck_irq, kp); free_irq(kp->key_sense_irq, kp); input_unregister_device(kp->input); platform_set_drvdata(pdev, NULL); kfree(kp->input->keycode); kfree(kp); return 0; } #ifdef CONFIG_PM static int pmic8058_kp_suspend(struct device *dev) { struct pmic8058_kp *kp = dev_get_drvdata(dev); if (device_may_wakeup(dev) && !pmic8058_kp_disabled(kp)) { enable_irq_wake(kp->key_sense_irq); } else { mutex_lock(&kp->mutex); pmic8058_kp_disable(kp); mutex_unlock(&kp->mutex); } return 0; } static int pmic8058_kp_resume(struct device *dev) { struct pmic8058_kp *kp = dev_get_drvdata(dev); if (device_may_wakeup(dev) && !pmic8058_kp_disabled(kp)) { disable_irq_wake(kp->key_sense_irq); } else { mutex_lock(&kp->mutex); pmic8058_kp_enable(kp); mutex_unlock(&kp->mutex); } return 0; } static struct dev_pm_ops pm8058_kp_pm_ops = { .suspend = pmic8058_kp_suspend, .resume = pmic8058_kp_resume, }; #endif static struct platform_driver pmic8058_kp_driver = { .probe = pmic8058_kp_probe, .remove = __devexit_p(pmic8058_kp_remove), .driver = { .name = "pm8058-keypad", .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &pm8058_kp_pm_ops, #endif }, }; static int __init pmic8058_kp_init(void) { return platform_driver_register(&pmic8058_kp_driver); } module_init(pmic8058_kp_init); static void __exit pmic8058_kp_exit(void) { platform_driver_unregister(&pmic8058_kp_driver); }
static int gpio_keypad_config(struct pmic8058_kp *kp) { struct pm8058_gpio gpiokpd_configuration = { .direction = PM_GPIO_DIR_IN, .pull = PM_GPIO_PULL_UP_31P5, .vin_sel = 2, .out_strength = PM_GPIO_STRENGTH_NO, .function = PM_GPIO_FUNC_NORMAL, .inv_int_pol = 0, }; int rc = 0; //------- rc = pm8058_gpio_config(SILENT_KEY_UP_GPIO, &gpiokpd_configuration); //Div2D5-OwenHung-Silent Key GPIO shift+ if (rc < 0) { printk(KERN_ERR "[KEYPAD] Config GPIO %d fail", SILENT_KEY_UP_GPIO); return rc; } else { rc = gpio_request(PM8058_GPIO_PM_TO_SYS(SILENT_KEY_UP_GPIO), "silent_key_up"); //Div2D5-OwenHung-Silent Key GPIO shift+ if (rc < 0) { printk(KERN_ERR "[KEYPAD] GPIO request - %d fail", SILENT_KEY_UP_GPIO); return rc; } else { rc = gpio_direction_input(PM8058_GPIO_PM_TO_SYS(SILENT_KEY_UP_GPIO) ); //Div2D5-OwenHung-Silent Key GPIO shift+ if (rc < 0) { printk(KERN_ERR "[KEYPAD] GPIO direction - %d fail", SILENT_KEY_UP_GPIO); return rc; } } } printk(KERN_INFO "[KEYPAD] Config GPIO %d OK", SILENT_KEY_UP_GPIO); return rc; } #endif //Div2D5-OwenHung-keypad driver porting- /* * NOTE: Last row multi-interrupt issue * * In PMIC Rev A0, if any key in the last row of the keypad matrix * is pressed and held, the H/W keeps on generating interrupts. * Software work-arounds it by programming the keypad controller next level * up rows (for 8x12 matrix it is 15 rows) so the keypad controller * thinks of more-rows than the actual ones, so the actual last-row * in the matrix won't generate multiple interrupts. */ static int pmic8058_kpd_init(struct pmic8058_kp *kp) { int bits, rc, cycles; u8 scan_val = 0, ctrl_val = 0; static u8 row_bits[] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, }; /* Find column bits */ if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN) bits = 0; else bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN; ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) << KEYP_CTRL_SCAN_COLS_SHIFT; /* Find row bits */ if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN) bits = 0; else if (kp->pdata->num_rows > PM8058_MAX_ROWS) bits = KEYP_CTRL_SCAN_ROWS_BITS; else bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN]; /* Use max rows to fix last row problem if actual rows are less */ if (kp->flags & KEYF_FIX_LAST_ROW && (kp->pdata->num_rows != PM8058_MAX_ROWS)) bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN + 1]; ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT); rc = pmic8058_kp_write_u8(kp, ctrl_val, KEYP_CTRL); if (pm8058_rev(kp->pm_chip) == PM_8058_REV_1p0) bits = fls(kp->pdata->debounce_ms[0]) - 1; else bits = (kp->pdata->debounce_ms[1] / 5) - 1; scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT); bits = fls(kp->pdata->scan_delay_ms) - 1; scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT); /* Row hold time is a multiple of 32KHz cycles. */ cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC; scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT); rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN); return rc; }
static int pm8058_kp_config_drv(int gpio_start, int num_gpios) { int rc; struct pm8058_gpio kypd_drv = { .direction = PM_GPIO_DIR_OUT, .output_buffer = PM_GPIO_OUT_BUF_OPEN_DRAIN, .output_value = 0, .pull = PM_GPIO_PULL_NO, .vin_sel = 2, .out_strength = PM_GPIO_STRENGTH_LOW, .function = PM_GPIO_FUNC_1, .inv_int_pol = 1, }; if (gpio_start < 0 || num_gpios < 0 || num_gpios > PM8058_GPIOS) return -EINVAL; while (num_gpios--) { rc = pm8058_gpio_config(gpio_start++, &kypd_drv); if (rc) { pr_err("%s: FAIL pm8058_gpio_config(): rc=%d.\n", __func__, rc); return rc; } } return 0; } static int pm8058_kp_config_sns(int gpio_start, int num_gpios) { int rc; struct pm8058_gpio kypd_sns = { .direction = PM_GPIO_DIR_IN, .pull = PM_GPIO_PULL_UP_31P5, .vin_sel = 2, .out_strength = PM_GPIO_STRENGTH_NO, .function = PM_GPIO_FUNC_NORMAL, .inv_int_pol = 1, }; if (gpio_start < 0 || num_gpios < 0 || num_gpios > PM8058_GPIOS) return -EINVAL; while (num_gpios--) { rc = pm8058_gpio_config(gpio_start++, &kypd_sns); if (rc) { pr_err("%s: FAIL pm8058_gpio_config(): rc=%d.\n", __func__, rc); return rc; } } return 0; } static int __devinit pmic8058_kp_probe(struct platform_device *pdev) { struct pmic8058_keypad_data *pdata = pdev->dev.platform_data; struct pmic8058_kp *kp; int rc, i; unsigned short *keycodes; u8 ctrl_val; struct pm8058_chip *pm_chip; pm_chip = platform_get_drvdata(pdev); if (pm_chip == NULL) { dev_err(&pdev->dev, "no parent data passed in\n"); return -EFAULT; } if (!pdata || !pdata->num_cols || !pdata->num_rows || pdata->num_cols > MATRIX_MAX_COLS || pdata->num_rows > MATRIX_MAX_ROWS || pdata->num_cols < MATRIX_MIN_COLS || pdata->num_rows < MATRIX_MIN_ROWS || !pdata->keymap) { dev_err(&pdev->dev, "invalid platform data\n"); return -EINVAL; } if (pdata->rows_gpio_start < 0 || pdata->cols_gpio_start < 0) { dev_err(&pdev->dev, "invalid gpio_start platform data\n"); return -EINVAL; } if (!pdata->scan_delay_ms || pdata->scan_delay_ms > MAX_SCAN_DELAY || pdata->scan_delay_ms < MIN_SCAN_DELAY || !is_power_of_2(pdata->scan_delay_ms)) { dev_err(&pdev->dev, "invalid keypad scan time supplied\n"); return -EINVAL; } if (!pdata->row_hold_ns || pdata->row_hold_ns > MAX_ROW_HOLD_DELAY || pdata->row_hold_ns < MIN_ROW_HOLD_DELAY || ((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) { dev_err(&pdev->dev, "invalid keypad row hold time supplied\n"); return -EINVAL; } if (pm8058_rev(pm_chip) == PM_8058_REV_1p0) { if (!pdata->debounce_ms || !is_power_of_2(pdata->debounce_ms[0]) || pdata->debounce_ms[0] > MAX_DEBOUNCE_A0_TIME || pdata->debounce_ms[0] < MIN_DEBOUNCE_A0_TIME) { dev_err(&pdev->dev, "invalid debounce time supplied\n"); return -EINVAL; } } else { if (!pdata->debounce_ms || ((pdata->debounce_ms[1] % 5) != 0) || pdata->debounce_ms[1] > MAX_DEBOUNCE_B0_TIME || pdata->debounce_ms[1] < MIN_DEBOUNCE_B0_TIME) { dev_err(&pdev->dev, "invalid debounce time supplied\n"); return -EINVAL; } } kp = kzalloc(sizeof(*kp), GFP_KERNEL); if (!kp) return -ENOMEM; keycodes = kzalloc(MATRIX_MAX_SIZE * sizeof(keycodes), GFP_KERNEL); if (!keycodes) { rc = -ENOMEM; goto err_alloc_mem; } platform_set_drvdata(pdev, kp); kp->pdata = pdata; kp->dev = &pdev->dev; kp->keycodes = keycodes; kp->pm_chip = pm_chip; if (pm8058_rev(pm_chip) == PM_8058_REV_1p0) kp->flags |= KEYF_FIX_LAST_ROW; kp->input = input_allocate_device(); if (!kp->input) { dev_err(&pdev->dev, "unable to allocate input device\n"); rc = -ENOMEM; goto err_alloc_device; } kp->key_sense_irq = platform_get_irq(pdev, 0); if (kp->key_sense_irq < 0) { dev_err(&pdev->dev, "unable to get keypad sense irq\n"); rc = -ENXIO; goto err_get_irq; } kp->key_stuck_irq = platform_get_irq(pdev, 1); if (kp->key_stuck_irq < 0) { dev_err(&pdev->dev, "unable to get keypad stuck irq\n"); rc = -ENXIO; goto err_get_irq; } if (pdata->input_name) kp->input->name = pdata->input_name; else kp->input->name = "PMIC8058 keypad"; if (pdata->input_phys_device) kp->input->phys = pdata->input_phys_device; else kp->input->phys = "pmic8058_keypad/input0"; kp->input->dev.parent = &pdev->dev; kp->input->id.bustype = BUS_HOST; kp->input->id.version = 0x0001; kp->input->id.product = 0x0001; kp->input->id.vendor = 0x0001; kp->input->evbit[0] = BIT_MASK(EV_KEY); if (pdata->rep) __set_bit(EV_REP, kp->input->evbit); kp->input->keycode = keycodes; kp->input->keycodemax = MATRIX_MAX_SIZE; kp->input->keycodesize = sizeof(*keycodes); for (i = 0; i < pdata->keymap_size; i++) { unsigned int row = KEY_ROW(pdata->keymap[i]); unsigned int col = KEY_COL(pdata->keymap[i]); unsigned short keycode = KEY_VAL(pdata->keymap[i]); keycodes[(row << 3) + col] = keycode; __set_bit(keycode, kp->input->keybit); } __clear_bit(KEY_RESERVED, kp->input->keybit); input_set_capability(kp->input, EV_MSC, MSC_SCAN); input_set_drvdata(kp->input, kp); rc = input_register_device(kp->input); if (rc < 0) { dev_err(&pdev->dev, "unable to register keypad input device\n"); goto err_get_irq; } memset(kp->keystate, 0xff, sizeof(kp->keystate)); memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate)); rc = pmic8058_kpd_init(kp); if (rc < 0) { dev_err(&pdev->dev, "unable to initialize keypad controller\n"); goto err_kpd_init; } rc = pm8058_kp_config_sns(pdata->cols_gpio_start, pdata->num_cols); if (rc < 0) { dev_err(&pdev->dev, "unable to configure keypad sense lines\n"); goto err_gpio_config; } rc = pm8058_kp_config_drv(pdata->rows_gpio_start, pdata->num_rows); if (rc < 0) { dev_err(&pdev->dev, "unable to configure keypad drive lines\n"); goto err_gpio_config; } rc = request_irq(kp->key_sense_irq, pmic8058_kp_irq, IRQF_TRIGGER_RISING, "pmic-keypad", kp); if (rc < 0) { dev_err(&pdev->dev, "failed to request keypad sense irq\n"); goto err_req_sense_irq; } rc = request_irq(kp->key_stuck_irq, pmic8058_kp_stuck_irq, IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp); if (rc < 0) { dev_err(&pdev->dev, "failed to request keypad stuck irq\n"); goto err_req_stuck_irq; } rc = pmic8058_kp_read(kp, &ctrl_val, KEYP_CTRL, 1); ctrl_val |= KEYP_CTRL_KEYP_EN; rc = pmic8058_kp_write_u8(kp, ctrl_val, KEYP_CTRL); __dump_kp_regs(kp, "probe"); device_init_wakeup(&pdev->dev, pdata->wakeup); return 0; err_req_stuck_irq: free_irq(kp->key_sense_irq, NULL); err_req_sense_irq: err_gpio_config: err_kpd_init: input_unregister_device(kp->input); kp->input = NULL; err_get_irq: input_free_device(kp->input); err_alloc_device: kfree(keycodes); err_alloc_mem: kfree(kp); return rc; } static int __devexit pmic8058_kp_remove(struct platform_device *pdev) { struct pmic8058_kp *kp = platform_get_drvdata(pdev); device_init_wakeup(&pdev->dev, 0); free_irq(kp->key_stuck_irq, NULL); free_irq(kp->key_sense_irq, NULL); input_unregister_device(kp->input); platform_set_drvdata(pdev, NULL); kfree(kp->input->keycode); kfree(kp); return 0; } static struct platform_driver pmic8058_kp_driver = { .probe = pmic8058_kp_probe, .remove = __devexit_p(pmic8058_kp_remove), .driver = { .name = "pm8058-keypad", .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &pm8058_kp_pm_ops, #endif }, }; static int __init pmic8058_kp_init(void) { return platform_driver_register(&pmic8058_kp_driver); } module_init(pmic8058_kp_init); static void __exit pmic8058_kp_exit(void) { platform_driver_unregister(&pmic8058_kp_driver); }
static int pmic8058_kp_read_matrix(struct pmic8058_kp *kp, u16 *new_state, u16 *old_state) { /* SHARP Add. use 1 Row Line. other key data clear. start */ #ifdef CONFIG_KEYBOARD_SCKEY #if (defined(CONFIG_QWERTY_KEYPAD) || defined(CONFIG_QWERTY2_KEYPAD) || defined(CONFIG_QWERTY3_KEYPAD)) volatile int j,i,k = 0; volatile int bits_changed1; volatile int bits_changed2; volatile int bits_changed_old1; volatile int bits_changed_old2; volatile int board_state; volatile int result; #else int j; #endif /* (defined(CONFIG_QWERTY_KEYPAD) || defined(CONFIG_QWERTY2_KEYPAD) || defined(CONFIG_QWERTY3_KEYPAD)) */ #endif /* #ifdef CONFIG_KEYBOARD_SCKEY */ /* SHARP Add. use 1 Row Line. end */ int rc, read_rows; u8 scan_val; static u8 rows[] = { 5, 6, 7, 8, 10, 10, 12, 12, 15, 15, 15, 18, 18, 18 }; if (kp->flags & KEYF_FIX_LAST_ROW && (kp->pdata->num_rows != PM8058_MAX_ROWS)) read_rows = rows[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN + 1]; else read_rows = kp->pdata->num_rows; if (pm8058_rev(kp->pm_chip) > PM_8058_REV_1p0) pmic8058_chk_sync_read(kp); if (old_state) rc = pmic8058_kp_read_data(kp, old_state, KEYP_OLD_DATA, read_rows); rc = pmic8058_kp_read_data(kp, new_state, KEYP_RECENT_DATA, read_rows); if (pm8058_rev(kp->pm_chip) > PM_8058_REV_1p0) { /* 4 * 32KHz clocks */ udelay((4 * USEC_PER_SEC / KEYP_CLOCK_FREQ) + 1); rc = pmic8058_kp_read(kp, &scan_val, KEYP_SCAN, 1); scan_val &= 0xFE; rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN); } /* SHARP Add. use 1 Row Line. other key data clear. start */ #ifdef CONFIG_KEYBOARD_SCKEY #if (defined(CONFIG_TENKEY_KEYPAD) || defined(CONFIG_TENKEY2_KEYPAD) || defined(CONFIG_TENKEY3_KEYPAD)) /* depend on target system */ for( j = 6; j <MATRIX_MAX_ROWS; j++) { if (old_state) { old_state[j] = 0xff; } new_state[j] = 0xff; } #elif (defined(CONFIG_QWERTY_KEYPAD) || defined(CONFIG_QWERTY2_KEYPAD) || defined(CONFIG_QWERTY3_KEYPAD)) result = sh_boot_get_hw_revision(); if( (result & 0x0002) == 0 ) { board_state = 0; } else { board_state =1; } SHDBG_KEY_HAL(printk(KERN_DEBUG "[shkey]result:0x%x,board_state:0x%x\n", result ,board_state);) /* depend on target system */ for( j = 10; j <MATRIX_MAX_ROWS; j++)
/* * keypad controller should be initialized in the following sequence * only, otherwise it might get into FSM stuck state. * * - Initialize keypad control parameters, like no. of rows, columns, * timing values etc., * - configure rows and column gpios pull up/down. * - set irq edge type. * - enable the keypad controller. */ static int __devinit pmic8058_kp_probe(struct platform_device *pdev) { struct pmic8058_keypad_data *pdata = pdev->dev.platform_data; struct pmic8058_kp *kp; int rc, i; unsigned short *keycodes; u8 ctrl_val; if (!pdata || !pdata->num_cols || !pdata->num_rows || pdata->num_cols > MATRIX_MAX_COLS || pdata->num_rows > MATRIX_MAX_ROWS || !pdata->keymap) { dev_err(&pdev->dev, "invalid platform data\n"); return -EINVAL; } if (pdata->rows_gpio_start < 0 || pdata->cols_gpio_start < 0) { dev_err(&pdev->dev, "invalid gpio_start platform data\n"); return -EINVAL; } if (!pdata->scan_delay_ms || pdata->scan_delay_ms > MAX_SCAN_DELAY || pdata->scan_delay_ms < MIN_SCAN_DELAY || !is_power_of_2(pdata->scan_delay_ms)) { dev_err(&pdev->dev, "invalid keypad scan time supplied\n"); return -EINVAL; } rc = pm8058_read(PM8058_REV, &rev, 1); pr_info("PMIC4 is at %X revision\n", rev); if (rev == PMIC8058_REV_A0) { if (!pdata->debounce_ms || !is_power_of_2(pdata->debounce_ms) || pdata->debounce_ms > MAX_DEBOUNCE_A0_TIME || pdata->debounce_ms < MIN_DEBOUNCE_A0_TIME) { dev_err(&pdev->dev, "invalid debounce time supplied\n"); return -EINVAL; } } else { if (!pdata->debounce_ms || ((pdata->debounce_ms % 5) != 0) || pdata->debounce_ms > MAX_DEBOUNCE_B0_TIME || pdata->debounce_ms < MIN_DEBOUNCE_B0_TIME) { dev_err(&pdev->dev, "invalid debounce time supplied\n"); return -EINVAL; } } kp = kzalloc(sizeof(*kp), GFP_KERNEL); if (!kp) return -ENOMEM; keycodes = kzalloc(MATRIX_MAX_SIZE * sizeof(keycodes), GFP_KERNEL); if (!keycodes) { rc = -ENOMEM; goto err_alloc_mem; } platform_set_drvdata(pdev, kp); kp->pdata = pdata; kp->dev = &pdev->dev; kp->keycodes = keycodes; /* REVISIT: actual revision with the fix */ if (rev <= PMIC8058_REV_B0) kp->flags |= KEYF_FIX_LAST_ROW; kp->input = input_allocate_device(); if (!kp->input) { dev_err(&pdev->dev, "unable to allocate input device\n"); rc = -ENOMEM; goto err_alloc_device; } kp->key_sense_irq = platform_get_irq(pdev, 0); if (kp->key_sense_irq < 0) { dev_err(&pdev->dev, "unable to get keypad sense irq\n"); rc = -ENXIO; goto err_get_irq; } kp->key_stuck_irq = platform_get_irq(pdev, 1); if (kp->key_stuck_irq < 0) { dev_err(&pdev->dev, "unable to get keypad stuck irq\n"); rc = -ENXIO; goto err_get_irq; } if (pdata->input_name) kp->input->name = pdata->input_name; else kp->input->name = "PMIC8058 keypad"; if (pdata->input_phys_device) kp->input->phys = pdata->input_phys_device; else kp->input->phys = "pmic8058_keypad/input0"; kp->input->dev.parent = &pdev->dev; kp->input->id.bustype = BUS_HOST; kp->input->id.version = 0x0001; kp->input->id.product = 0x0001; kp->input->id.vendor = 0x0001; kp->input->evbit[0] = BIT_MASK(EV_KEY); if (pdata->rep) __set_bit(EV_REP, kp->input->evbit); kp->input->keycode = keycodes; kp->input->keycodemax = MATRIX_MAX_SIZE; kp->input->keycodesize = sizeof(*keycodes); /* build keycodes for faster scanning */ for (i = 0; i < pdata->keymap_size; i++) { unsigned int row = KEY_ROW(pdata->keymap[i]); unsigned int col = KEY_COL(pdata->keymap[i]); unsigned short keycode = KEY_VAL(pdata->keymap[i]); keycodes[(row << 3) + col] = keycode; __set_bit(keycode, kp->input->keybit); } __clear_bit(KEY_RESERVED, kp->input->keybit); input_set_capability(kp->input, EV_MSC, MSC_SCAN); input_set_drvdata(kp->input, kp); rc = input_register_device(kp->input); if (rc < 0) { dev_err(&pdev->dev, "unable to register keypad input device\n"); goto err_get_irq; } /* initialize keypad state */ memset(kp->keystate, 0xff, sizeof(kp->keystate)); rc = pmic8058_kpd_init(kp); if (rc < 0) { dev_err(&pdev->dev, "unable to initialize keypad controller\n"); goto err_kpd_init; } rc = pm8058_gpio_config_kypd_sns(pdata->cols_gpio_start, pdata->num_cols); if (rc < 0) { dev_err(&pdev->dev, "unable to configure keypad sense lines\n"); goto err_gpio_config; } rc = pm8058_gpio_config_kypd_drv(pdata->rows_gpio_start, pdata->num_rows); if (rc < 0) { dev_err(&pdev->dev, "unable to configure keypad drive lines\n"); goto err_gpio_config; } rc = request_irq(kp->key_sense_irq, pmic8058_kp_irq, IRQF_TRIGGER_RISING, "pmic-keypad", kp); if (rc < 0) { dev_err(&pdev->dev, "failed to request keypad sense irq\n"); goto err_req_sense_irq; } rc = request_irq(kp->key_stuck_irq, pmic8058_kp_stuck_irq, IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp); if (rc < 0) { dev_err(&pdev->dev, "failed to request keypad stuck irq\n"); goto err_req_stuck_irq; } rc = pmic8058_kp_read(kp, &ctrl_val, KEYP_CTRL, 1); ctrl_val |= KEYP_CTRL_KEYP_EN; rc = pmic8058_kp_write_u8(kp, ctrl_val, KEYP_CTRL); __dump_kp_regs(kp, "probe"); device_init_wakeup(&pdev->dev, pdata->wakeup); return 0; err_req_stuck_irq: free_irq(kp->key_sense_irq, NULL); err_req_sense_irq: err_gpio_config: err_kpd_init: input_unregister_device(kp->input); kp->input = NULL; err_get_irq: input_free_device(kp->input); err_alloc_device: kfree(keycodes); err_alloc_mem: kfree(kp); return rc; }