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; }
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; }
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; }
/** * 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; }
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; }
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; }