int pm8058_gpio_config_kypd_drv(int gpio_start, int num_gpios, unsigned mach_id)
{
	int	rc;
	struct pm8058_gpio kypd_drv = {
		.direction	= PM_GPIO_DIR_OUT,
		.pull		= PM_GPIO_PULL_NO,
		.vin_sel	= 2,
		.out_strength	= PM_GPIO_STRENGTH_LOW,
		.function	= PM_GPIO_FUNC_1,
		.inv_int_pol	= 1,
	};

	if(mach_id == LINUX_MACHTYPE_8660_QT)
		kypd_drv.function = PM_GPIO_FUNC_NORMAL;

	while (num_gpios--) {
		rc = pm8058_gpio_config(gpio_start++, &kypd_drv);
		if (rc) {
		        dprintf(INFO, "FAIL pm8058_gpio_config(): rc=%d.\n", rc);
			return rc;
		}
	}

	return 0;
}

int pm8058_gpio_config_kypd_sns(int gpio_start, int num_gpios)
{
	int	rc;
	struct pm8058_gpio kypd_sns = {
		.direction	= PM_GPIO_DIR_IN,
		.pull		= PM_GPIO_PULL_UP1,
		.vin_sel	= 2,
		.out_strength	= PM_GPIO_STRENGTH_NO,
		.function	= PM_GPIO_FUNC_NORMAL,
		.inv_int_pol	= 1,
	};

	while (num_gpios--) {
		rc = pm8058_gpio_config(gpio_start++, &kypd_sns);
		if (rc) {
		        dprintf(INFO, "FAIL pm8058_gpio_config(): rc=%d.\n", rc);
			return rc;
		}
	}

	return 0;
}

static void ssbi_gpio_init(unsigned int mach_id)
{
    unsigned char kypd_cntl_init;
    unsigned char kypd_scan_init = 0x20;
    int rows = (qwerty_keypad->keypad_info)->rows;
    int columns = (qwerty_keypad->keypad_info)->columns;
    write_func wr_function = (qwerty_keypad->keypad_info)->wr_func;
    unsigned char drv_bits[] = {
	    0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7 };
    unsigned char sns_bits[] = { 0, 0, 0, 0, 0, 0, 1, 2, 3 };

    kypd_cntl_init = ((drv_bits[rows] << 2) | (sns_bits[columns] << 5) | (1 << 7));

    if ((*wr_function)(&kypd_cntl_init, 1, SSBI_REG_KYPD_CNTL_ADDR))
      dprintf (CRITICAL, "Error in initializing SSBI_REG_KYPD_CNTL register\n");

    if ((*wr_function)(&kypd_scan_init, 1, SSBI_REG_KYPD_SCAN_ADDR))
      dprintf (CRITICAL, "Error in initializing SSBI_REG_KYPD_SCAN register\n");

    if(mach_id == LINUX_MACHTYPE_8660_QT)
    {
        pm8058_gpio_config_kypd_sns(QT_PMIC_GPIO_KYPD_SNS, rows);
        pm8058_gpio_config_kypd_drv(QT_PMIC_GPIO_KYPD_DRV,  columns, mach_id);
    }
    else
    {
        pm8058_gpio_config_kypd_sns(SSBI_OFFSET_ADDR_GPIO_KYPD_SNS, columns);
        pm8058_gpio_config_kypd_drv(SSBI_OFFSET_ADDR_GPIO_KYPD_DRV,  rows, mach_id);
    }
}
Exemplo n.º 2
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;
}