Ejemplo n.º 1
0
static int pmic8058_kp_read_u8(struct pmic8058_kp *kp,
				 u8 *data, u16 reg)
{
	int rc;

	rc = pmic8058_kp_read(kp, data, reg, 1);
	if (rc < 0)
		dev_warn(kp->dev, "Error reading pmic8058: %X - ret %X\n",
				reg, rc);
	return rc;
}
Ejemplo n.º 2
0
static int pmic8058_kp_read_matrix(struct pmic8058_kp *kp, u16 *new_state,
					 u16 *old_state)
{
	int rc, row, read_rows;
	u8 new_data[MATRIX_MAX_ROWS];
	u8 old_data[MATRIX_MAX_ROWS];

	if (kp->flags & KEYF_FIX_LAST_ROW)
		read_rows = MATRIX_MAX_ROWS;
	else
		read_rows = kp->pdata->num_rows;

	rc = pmic8058_kp_read(kp, new_data, KEYP_RECENT_DATA,
			      read_rows);

	if (!rc) {
		pmic8058_chk_read_state(kp, 1);
		for (row = 0; row < kp->pdata->num_rows; row++) {
			dev_dbg(kp->dev, "new_data[%d] = %d\n", row,
						new_data[row]);
			new_state[row] = pmic8058_col_state(kp, new_data[row]);
		}
	}

	if (old_state) {
		rc = pmic8058_kp_read(kp, old_data, KEYP_OLD_DATA,
				read_rows);
		if (!rc) {
			pmic8058_chk_read_state(kp, 0);
			for (row = 0; row < kp->pdata->num_rows; row++) {
				dev_dbg(kp->dev, "old_data[%d] = %d\n", row,
						 old_data[row]);
				old_state[row] = pmic8058_col_state(kp,
							 old_data[row]);
			}
		}
	}

	return rc;
}
Ejemplo n.º 3
0
/* H/W constraint:
 * One should read recent/old data registers equal to the
 * number of columns programmed in the keyp_control register,
 * otherwise h/w state machine may get stuck. In order to avoid this
 * situation one should check readstate bit in keypad scan
 * register to be '0' at the end of data read, to make sure
 * the keypad state machine is not in READ state.
 */
static int pmic8058_chk_read_state(struct pmic8058_kp *kp, u8 flag)
{
	u8 temp, scan_val;
	int retries = 10, rc;

	do {
		rc = pmic8058_kp_read(kp, &scan_val, KEYP_SCAN, 1);
		if (scan_val & 0x1) {
			if (flag)
				rc = pmic8058_kp_read(kp, &temp,
							 KEYP_RECENT_DATA, 1);
			else
				rc = pmic8058_kp_read(kp, &temp,
							 KEYP_OLD_DATA, 1);
		}
	} while ((scan_val & 0x1) && (--retries > 0));

	if (retries == 0)
		dev_dbg(kp->dev, "Unable to clear read state bit\n");

	return 0;
}
Ejemplo n.º 4
0
static irqreturn_t pmic8058_kp_irq(int irq, void *data)
{
	struct pmic8058_kp *kp = data;
	u8 ctrl_val, events;
	int rc;

	dev_dbg(kp->dev, "key sense irq\n");
	__dump_kp_regs(kp, "pmic8058_kp_irq");

	rc = pmic8058_kp_read(kp, &ctrl_val, KEYP_CTRL, 1);
	events = ctrl_val & KEYP_CTRL_EVNTS_MASK;

	rc = pmic8058_kp_scan_matrix(kp, events);

	return IRQ_HANDLED;
}
Ejemplo n.º 5
0
/*
 * NOTE: Any row multiple interrupt issue - PMIC4 Rev A0
 *
 * If the S/W responds to the key-event interrupt too early and reads the
 * recent data, the keypad FSM will mistakenly go to the IDLE state, instead
 * of the scan pause state as it is supposed too. Since the key is still
 * pressed, the keypad scanner will go through the debounce, scan, and generate
 * another key event interrupt. The workaround for this issue is to add delay
 * of 1ms between servicing the key event interrupt and reading the recent data.
 */
static irqreturn_t pmic8058_kp_irq(int irq, void *data)
{
	struct pmic8058_kp *kp = data;
	u8 ctrl_val, events;
	int rc;

	if (pm8058_rev(kp->pm_chip) == PM_8058_REV_1p0)
		mdelay(1);

	pr_info("key sense irq\n");
	dev_dbg(kp->dev, "key sense irq\n");
	__dump_kp_regs(kp, "pmic8058_kp_irq");

	rc = pmic8058_kp_read(kp, &ctrl_val, KEYP_CTRL, 1);
	events = ctrl_val & KEYP_CTRL_EVNTS_MASK;

	rc = pmic8058_kp_scan_matrix(kp, events);

	return IRQ_HANDLED;
}
Ejemplo n.º 6
0
static int pmic8058_kp_read_data(struct pmic8058_kp *kp, u16 *state,
					u16 data_reg, int read_rows)
{
	int rc, row;
	u8 new_data[PM8058_MAX_ROWS];

	rc = pmic8058_kp_read(kp, new_data, data_reg, read_rows);

	if (!rc) {
		if (pm8058_rev(kp->pm_chip) == PM_8058_REV_1p0)
			pmic8058_chk_read_state(kp, data_reg);
		for (row = 0; row < kp->pdata->num_rows; row++) {
			dev_dbg(kp->dev, "new_data[%d] = %d\n", row,
						new_data[row]);
			state[row] = pmic8058_col_state(kp, new_data[row]);
		}
	}

	return rc;
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
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);
}
Ejemplo n.º 9
0
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++)
Ejemplo n.º 10
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;
	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;
}