示例#1
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;
}
示例#2
0
/*
 * 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;
}
示例#3
0
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;
}
/*
 * 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);

	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;
}
示例#5
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;
}
示例#6
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;
}

/*
 * 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);
}
示例#7
0
static int __devinit pm8058_othc_probe(struct platform_device *pd)
{
	int rc;
	struct pm8058_othc *dd;
	struct pm8058_chip *chip;
	struct resource *res;
	struct pmic8058_othc_config_pdata *pdata = pd->dev.platform_data;

	chip = platform_get_drvdata(pd);
	if (chip == NULL) {
		pr_err("%s: Invalid driver information \n", __func__);
		return  -EINVAL;
	}

	/* Check PMIC8058 version. A0 version is not supported */
	if (pm8058_rev(chip) == PM_8058_REV_1p0) {
		pr_err("%s: PMIC8058 version not supported \n", __func__);
		return -ENODEV;
	}

	if (pdata == NULL) {
		pr_err("%s: Platform data not present \n", __func__);
		return -EINVAL;
	}

	dd = kzalloc(sizeof(*dd), GFP_KERNEL);
	if (dd == NULL) {
		pr_err("%s: Unable to allocate memory \n", __func__);
		return -ENOMEM;
	}

	/* Enable runtime PM ops, start in ACTIVE mode */
	rc = pm_runtime_set_active(&pd->dev);
	if (rc < 0)
		dev_dbg(&pd->dev, "unable to set runtime pm state\n");
	pm_runtime_enable(&pd->dev);

	res = platform_get_resource_byname(pd, IORESOURCE_IO, "othc_base");
	if (res == NULL) {
		pr_err("%s: othc resource:Base address absent \n", __func__);
		rc = -ENXIO;
		goto fail_get_res;
	}

	dd->othc_pdata = pdata;
	dd->pm_chip = chip;
	dd->othc_base = res->start;

	if (pdata->micbias_capability == OTHC_MICBIAS_HSED) {
		/* HSED to be supported on this MICBIAS line */
		if (pdata->hsed_config != NULL) {
			rc = othc_configure_hsed(dd, pd);
			if (rc < 0)
				goto fail_get_res;
		} else {
			pr_err("%s: HSED config data not present\n", __func__);
			rc = -EINVAL;
			goto fail_get_res;
		}
	}

	/* Store the local driver data structure */
	if (dd->othc_pdata->micbias_select < OTHC_MICBIAS_MAX)
		config[dd->othc_pdata->micbias_select] = dd;

	platform_set_drvdata(pd, dd);

	pr_debug("%s: Device %s:%d successfully registered\n",
				__func__, pd->name, pd->id);
	return 0;

fail_get_res:
	pm_runtime_set_suspended(&pd->dev);
	pm_runtime_disable(&pd->dev);

	kfree(dd);
	return rc;
}
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;
}
示例#9
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);
}
示例#10
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++)