コード例 #1
0
static ssize_t clk_enable_set(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	struct  fpc1145_data *fpc1145 = dev_get_drvdata(dev);
	int rc = set_clks(fpc1145, *buf == '1');
	return rc ? rc : count;
}
コード例 #2
0
static int fpc1020_resume(struct spi_device *spi)
{
	struct fpc1020_data *fpc1020 = dev_get_drvdata(&spi->dev);
	if (fpc1020->clocks_suspended)
		set_clks(fpc1020, true);
	return 0;
}
コード例 #3
0
static int fpc1020_suspend(struct spi_device * spi, pm_message_t mesg)
{
	struct fpc1020_data *fpc1020 = dev_get_drvdata(&spi->dev);
	fpc1020->clocks_suspended = fpc1020->clocks_enabled;
	set_clks(fpc1020, false);
	return 0;
}
コード例 #4
0
/**
 * Will setup clocks, GPIOs, and regulators to correctly initialize the touch
 * sensor to be ready for work.
 *
 * In the correct order according to the sensor spec this function will
 * enable/disable regulators, SPI platform clocks, and reset line, all to set
 * the sensor in a correct power on or off state "electrical" wise.
 *
 * @see  spi_prepare_set
 * @note This function will not send any commands to the sensor it will only
 *       control it "electrically".
 */
static int device_prepare(struct  fpc1145_data *fpc1145, bool enable)
{
	int rc;

	mutex_lock(&fpc1145->lock);
	if (enable && !fpc1145->prepared) {
		spi_bus_lock(fpc1145->spi->master);
		fpc1145->prepared = true;
		select_pin_ctl(fpc1145, "fpc1145_reset_reset");

		rc = vreg_setup(fpc1145, "vcc_spi", true);
		if (rc)
			goto exit;

		rc = vreg_setup(fpc1145, "vdd_io", true);
		if (rc)
			goto exit_1;

		rc = vreg_setup(fpc1145, "vdd_ana", true);
		if (rc)
			goto exit_2;

		usleep_range(100, 1000);

		rc = spi_set_fabric(fpc1145, true);
		if (rc)
			goto exit_3;
		rc = set_clks(fpc1145, true);
		if (rc)
			goto exit_4;

		(void)select_pin_ctl(fpc1145, "fpc1145_cs_high");
		(void)select_pin_ctl(fpc1145, "fpc1145_reset_active");
		usleep_range(100, 200);
		(void)select_pin_ctl(fpc1145, "fpc1145_cs_active");

		rc = set_pipe_ownership(fpc1145, true);
		if (rc)
			goto exit_5;
	} else if (!enable && fpc1145->prepared) {
		rc = 0;
		(void)set_pipe_ownership(fpc1145, false);
exit_5:
		(void)set_clks(fpc1145, false);
exit_4:
		(void)spi_set_fabric(fpc1145, false);
exit_3:
		(void)select_pin_ctl(fpc1145, "fpc1145_cs_high");
		(void)select_pin_ctl(fpc1145, "fpc1145_reset_reset");
		usleep_range(FPC1145_VREG_SETUP_US,
				FPC1145_VREG_SETUP_US + 100);

		(void)select_pin_ctl(fpc1145, "fpc1145_cs_low");
		usleep_range(FPC1145_VREG_SETUP_US,
				FPC1145_VREG_SETUP_US + 100);

exit_2:
		(void)vreg_setup(fpc1145, "vdd_ana", false);
exit_1:
		(void)vreg_setup(fpc1145, "vdd_io", false);
exit:
		(void)vreg_setup(fpc1145, "vcc_spi", false);
		fpc1145->prepared = false;
		spi_bus_unlock(fpc1145->spi->master);
	} else {
		rc = 0;
	}
	mutex_unlock(&fpc1145->lock);
	return rc;
}
コード例 #5
0
static int device_prepare(struct  fpc1020_data *fpc1020, bool enable)
{
	int rc;

	mutex_lock(&fpc1020->lock);
	if (enable && !fpc1020->prepared) {
		spi_bus_lock(fpc1020->spi->master);
		fpc1020->prepared = true;
		/* select_pin_ctl(fpc1020, "fpc1020_reset_reset"); */

		/*
		rc = vreg_setup(fpc1020, "vcc_spi", true);
		if (rc)
			goto exit;

		rc = vreg_setup(fpc1020, "vdd_io", true);
		if (rc)
			goto exit_1;

		rc = vreg_setup(fpc1020, "vdd_ana", true);
		if (rc)
			goto exit_2;
		*/
		usleep_range(100, 1000);

		rc = spi_set_fabric(fpc1020, true);
		if (rc)
			goto exit_3;
		rc = set_clks(fpc1020, true);
		if (rc)
			goto exit_4;

		/* (void)select_pin_ctl(fpc1020, "fpc1020_cs_high"); */
		/* (void)select_pin_ctl(fpc1020, "fpc1020_reset_active"); */
		usleep_range(100, 200);
		/* (void)select_pin_ctl(fpc1020, "fpc1020_cs_active"); */

#if defined(SUPPORT_TRUSTZONE)
		rc = set_pipe_ownership(fpc1020, true);
		if (rc)
			goto exit_5;
#endif
	} else if (!enable && fpc1020->prepared) {
		rc = 0;
#if defined(SUPPORT_TRUSTZONE)
		(void)set_pipe_ownership(fpc1020, false);
exit_5:
#endif
		(void)set_clks(fpc1020, false);
exit_4:
		(void)spi_set_fabric(fpc1020, false);
exit_3:
		(void)select_pin_ctl(fpc1020, "fpc1020_cs_high");
		(void)select_pin_ctl(fpc1020, "fpc1020_reset_reset");
		usleep_range(100, 1000);
/*
		(void)vreg_setup(fpc1020, "vdd_ana", false);
exit_2:
		(void)vreg_setup(fpc1020, "vdd_io", false);
exit_1:
		(void)vreg_setup(fpc1020, "vcc_spi", false);
exit:
*/
		(void)select_pin_ctl(fpc1020, "fpc1020_cs_low");

		fpc1020->prepared = false;
		spi_bus_unlock(fpc1020->spi->master);
	} else {
		rc = 0;
	}
	mutex_unlock(&fpc1020->lock);
	return rc;
}
コード例 #6
0
static int fpc1020_probe(struct spi_device *spi)
{
	struct device *dev = &spi->dev;
	struct device_node *np = dev->of_node;
	struct fpc1020_data *fpc1020;
	size_t i;
	int irqf = 0;
	int rc = 0;
	u32 val;
	fpc1020 = devm_kzalloc(dev, sizeof(*fpc1020), GFP_KERNEL);
	if (!fpc1020) {
		dev_err(dev, "failed to allocate memory\n");
		rc = -ENOMEM;
		goto exit;
	}

	fpc1020->dev = dev;
	dev_set_drvdata(dev, fpc1020);
	fpc1020->spi = spi;

	if (!np) {
		dev_err(dev, "of node found\n");
		rc = -EINVAL;
		goto exit;
	}

	rc = fpc1020_request_named_gpio(fpc1020, "fpc,gpio_irq",
			&fpc1020->irq_gpio);
	if (rc)
		goto exit;

	rc = fpc1020_request_named_gpio(fpc1020, "fpc,gpio_cs0",
			&fpc1020->cs0_gpio);
	if (rc)
		goto exit;

	rc = fpc1020_request_named_gpio(fpc1020, "fpc,gpio_rst",
			&fpc1020->rst_gpio);
	if (rc)
		goto exit;

	fpc1020->iface_clk = clk_get(dev, "iface_clk");
	if (IS_ERR(fpc1020->iface_clk)) {
		dev_err(dev, "%s: failed to get iface_clk\n", __func__);
		rc = -EINVAL;
		goto exit;
	}

	fpc1020->core_clk = clk_get(dev, "core_clk");
	if (IS_ERR(fpc1020->core_clk)) {
		dev_err(dev, "%s: failed to get core_clk\n", __func__);
		rc = -EINVAL;
		goto exit;
	}

	rc = of_property_read_u32(np, "qcom,spi-qup-id", &val);
	if (rc < 0) {
		dev_err(dev, "qcom,spi-qup-id not found\n");
		goto exit;
	}

	fpc1020->qup_id = val;
	dev_dbg(dev, "qcom,spi-qup-id %d\n", fpc1020->qup_id);

	fpc1020->fingerprint_pinctrl = devm_pinctrl_get(dev);
	if (IS_ERR(fpc1020->fingerprint_pinctrl)) {
		if (PTR_ERR(fpc1020->fingerprint_pinctrl) == -EPROBE_DEFER) {
			dev_info(dev, "pinctrl not ready\n");
			rc = -EPROBE_DEFER;
			goto exit;
		}
		dev_err(dev, "Target does not use pinctrl\n");
		fpc1020->fingerprint_pinctrl = NULL;
		rc = -EINVAL;
		goto exit;
	}

	for (i = 0; i < ARRAY_SIZE(fpc1020->pinctrl_state); i++) {
		const char *n = pctl_names[i];
		struct pinctrl_state *state =
			pinctrl_lookup_state(fpc1020->fingerprint_pinctrl, n);
		if (IS_ERR(state)) {
			dev_err(dev, "cannot find '%s'\n", n);
			rc = -EINVAL;
			goto exit;
		}
		dev_info(dev, "found pin control %s\n", n);
		fpc1020->pinctrl_state[i] = state;
	}

	select_pin_ctl(fpc1020, "fpc1020_reset_active");
	udelay(100);
	select_pin_ctl(fpc1020, "fpc1020_reset_reset");
	udelay(1000);
	select_pin_ctl(fpc1020, "fpc1020_reset_active");
	udelay(1250);
	rc = select_pin_ctl(fpc1020, "fpc1020_irq_active");
	if (rc)
		goto exit;

	rc = select_pin_ctl(fpc1020, "fpc1020_spi_active");
	if (rc)
		goto exit;

	fpc1020->wakeup_enabled = false;
	fpc1020->clocks_enabled = false;
	fpc1020->clocks_suspended = false;
	irqf = IRQF_TRIGGER_RISING | IRQF_ONESHOT;
	if (of_property_read_bool(dev->of_node, "fpc,enable-wakeup")) {
		irqf |= IRQF_NO_SUSPEND;
		device_init_wakeup(dev, 1);
	}

	mutex_init(&fpc1020->lock);
	rc = devm_request_threaded_irq(dev, gpio_to_irq(fpc1020->irq_gpio),
			NULL, fpc1020_irq_handler, irqf,
			dev_name(dev), fpc1020);
	if (rc) {
		dev_err(dev, "could not request irq %d\n",
				gpio_to_irq(fpc1020->irq_gpio));
		goto exit;
	}

	dev_dbg(dev, "requested irq %d\n", gpio_to_irq(fpc1020->irq_gpio));

	/* Request that the interrupt should be wakeable */
	enable_irq_wake( gpio_to_irq( fpc1020->irq_gpio ) );

	wake_lock_init(&fpc1020->ttw_wl, WAKE_LOCK_SUSPEND, "fpc_ttw_wl");

	rc = sysfs_create_group(&dev->kobj, &attribute_group);
	if (rc) {
		dev_err(dev, "could not create sysfs\n");
		goto exit;
	}

	if (of_property_read_bool(dev->of_node, "fpc,enable-on-boot")) {
		dev_info(dev, "enabling hardware\n");
		(void)device_prepare(fpc1020, true);
		(void)set_clks(fpc1020, false);
	}

	dev_info(dev, "%s: end\n", __func__);
exit:
	return rc;
}