Lines Matching +full:proximity +full:- +full:far +full:- +full:hysteresis
1 // SPDX-License-Identifier: GPL-2.0-only
4 * GP2AP002A00F Ambient Light and Proximity Sensor
5 * GP2AP002S00F Proximity Sensor
14 * https://lore.kernel.org/lkml/1315556546-7445-1-git-send-email-dg77.kim@samsung.com/
17 * https://lore.kernel.org/linux-input/20190125175045.22576-1-pawel.mikolaj.chmiel@gmail.com/
18 * Based partly on code from the Samsung GT-S7710 by <mjchen@sta.samsung.com>
42 /* ------------------------------------------------------------------------ */
45 /* ------------------------------------------------------------------------ */
52 /* ------------------------------------------------------------------------ */
53 /* VO :Proximity sensing result(0: no detection, 1: detection) */
54 /* LED0 :Select switch for LED driver's On-registence(0:2x higher, 1:normal)*/
76 * These bits adjusts the proximity sensitivity, determining characteristics
77 * of the detection distance and its hysteresis.
127 * struct gp2ap002 - GP2AP002 state
133 * @hys_far: hysteresis control from device tree
134 * @hys_close: hysteresis control from device tree
161 if (!gp2ap002->enabled) in gp2ap002_prox_irq()
164 ret = regmap_read(gp2ap002->map, GP2AP002_PROX, &val); in gp2ap002_prox_irq()
166 dev_err(gp2ap002->dev, "error reading proximity\n"); in gp2ap002_prox_irq()
172 dev_dbg(gp2ap002->dev, "close\n"); in gp2ap002_prox_irq()
173 ret = regmap_write(gp2ap002->map, GP2AP002_HYS, in gp2ap002_prox_irq()
174 gp2ap002->hys_far); in gp2ap002_prox_irq()
176 dev_err(gp2ap002->dev, in gp2ap002_prox_irq()
177 "error setting up proximity hysteresis\n"); in gp2ap002_prox_irq()
181 /* Far */ in gp2ap002_prox_irq()
182 dev_dbg(gp2ap002->dev, "far\n"); in gp2ap002_prox_irq()
183 ret = regmap_write(gp2ap002->map, GP2AP002_HYS, in gp2ap002_prox_irq()
184 gp2ap002->hys_close); in gp2ap002_prox_irq()
186 dev_err(gp2ap002->dev, in gp2ap002_prox_irq()
187 "error setting up proximity hysteresis\n"); in gp2ap002_prox_irq()
194 * After changing hysteresis, we need to wait for one detection in gp2ap002_prox_irq()
197 * register, we are hard-coding ~8 ms in probe() so wait some more in gp2ap002_prox_irq()
198 * than this, 20-30 ms. in gp2ap002_prox_irq()
203 ret = regmap_write(gp2ap002->map, GP2AP002_CON, in gp2ap002_prox_irq()
206 dev_err(gp2ap002->dev, "error setting up VOUT control\n"); in gp2ap002_prox_irq()
233 ret = iio_read_channel_processed(gp2ap002->alsout, &res); in gp2ap002_get_lux()
237 dev_dbg(gp2ap002->dev, "read %d mA from ADC\n", res); in gp2ap002_get_lux()
240 res = clamp(res, 0, (int)ARRAY_SIZE(gp2ap002_illuminance_table) - 1); in gp2ap002_get_lux()
253 pm_runtime_get_sync(gp2ap002->dev); in gp2ap002_read_raw()
257 switch (chan->type) { in gp2ap002_read_raw()
266 ret = -EINVAL; in gp2ap002_read_raw()
270 ret = -EINVAL; in gp2ap002_read_raw()
274 pm_runtime_mark_last_busy(gp2ap002->dev); in gp2ap002_read_raw()
275 pm_runtime_put_autosuspend(gp2ap002->dev); in gp2ap002_read_raw()
285 ret = regmap_write(gp2ap002->map, GP2AP002_GAIN, in gp2ap002_init()
288 dev_err(gp2ap002->dev, "error setting up LED gain\n"); in gp2ap002_init()
291 ret = regmap_write(gp2ap002->map, GP2AP002_HYS, gp2ap002->hys_far); in gp2ap002_init()
293 dev_err(gp2ap002->dev, in gp2ap002_init()
294 "error setting up proximity hysteresis\n"); in gp2ap002_init()
299 ret = regmap_write(gp2ap002->map, GP2AP002_CYCLE, in gp2ap002_init()
302 dev_err(gp2ap002->dev, in gp2ap002_init()
308 ret = regmap_write(gp2ap002->map, GP2AP002_OPMOD, in gp2ap002_init()
312 dev_err(gp2ap002->dev, "error setting up operation mode\n"); in gp2ap002_init()
317 ret = regmap_write(gp2ap002->map, GP2AP002_CON, in gp2ap002_init()
320 dev_err(gp2ap002->dev, "error setting up VOUT control\n"); in gp2ap002_init()
336 return gp2ap002->enabled; in gp2ap002_read_event_config()
353 pm_runtime_get_sync(gp2ap002->dev); in gp2ap002_write_event_config()
354 gp2ap002->enabled = true; in gp2ap002_write_event_config()
356 pm_runtime_mark_last_busy(gp2ap002->dev); in gp2ap002_write_event_config()
357 pm_runtime_put_autosuspend(gp2ap002->dev); in gp2ap002_write_event_config()
358 gp2ap002->enabled = false; in gp2ap002_write_event_config()
433 struct device *dev = &client->dev; in gp2ap002_probe()
448 return -ENOMEM; in gp2ap002_probe()
452 gp2ap002->dev = dev; in gp2ap002_probe()
464 gp2ap002->is_gp2ap002s00f = !strcmp(compat, "sharp,gp2ap002s00f"); in gp2ap002_probe()
471 gp2ap002->map = regmap; in gp2ap002_probe()
474 * The hysteresis settings are coded into the device tree as values in gp2ap002_probe()
475 * to be written into the hysteresis register. The datasheet defines in gp2ap002_probe()
479 * we allow passing an arbitrary hysteresis setting for "near" and in gp2ap002_probe()
480 * "far". in gp2ap002_probe()
483 /* Check the device tree for the IR LED hysteresis */ in gp2ap002_probe()
484 ret = device_property_read_u8(dev, "sharp,proximity-far-hysteresis", in gp2ap002_probe()
487 dev_err(dev, "failed to obtain proximity far setting\n"); in gp2ap002_probe()
490 dev_dbg(dev, "proximity far setting %02x\n", val); in gp2ap002_probe()
491 gp2ap002->hys_far = val; in gp2ap002_probe()
493 ret = device_property_read_u8(dev, "sharp,proximity-close-hysteresis", in gp2ap002_probe()
496 dev_err(dev, "failed to obtain proximity close setting\n"); in gp2ap002_probe()
499 dev_dbg(dev, "proximity close setting %02x\n", val); in gp2ap002_probe()
500 gp2ap002->hys_close = val; in gp2ap002_probe()
503 if (!gp2ap002->is_gp2ap002s00f) { in gp2ap002_probe()
504 gp2ap002->alsout = devm_iio_channel_get(dev, "alsout"); in gp2ap002_probe()
505 if (IS_ERR(gp2ap002->alsout)) { in gp2ap002_probe()
506 if (PTR_ERR(gp2ap002->alsout) == -ENODEV) { in gp2ap002_probe()
508 return -EPROBE_DEFER; in gp2ap002_probe()
511 return PTR_ERR(gp2ap002->alsout); in gp2ap002_probe()
513 ret = iio_get_channel_type(gp2ap002->alsout, &ch_type); in gp2ap002_probe()
519 return -EINVAL; in gp2ap002_probe()
523 gp2ap002->vdd = devm_regulator_get(dev, "vdd"); in gp2ap002_probe()
524 if (IS_ERR(gp2ap002->vdd)) { in gp2ap002_probe()
526 return PTR_ERR(gp2ap002->vdd); in gp2ap002_probe()
528 gp2ap002->vio = devm_regulator_get(dev, "vio"); in gp2ap002_probe()
529 if (IS_ERR(gp2ap002->vio)) { in gp2ap002_probe()
531 return PTR_ERR(gp2ap002->vio); in gp2ap002_probe()
535 ret = regulator_set_voltage(gp2ap002->vdd, 2400000, 3600000); in gp2ap002_probe()
542 ret = regulator_get_voltage(gp2ap002->vdd); in gp2ap002_probe()
547 ret = regulator_set_voltage(gp2ap002->vio, 1650000, ret); in gp2ap002_probe()
553 ret = regulator_enable(gp2ap002->vdd); in gp2ap002_probe()
558 ret = regulator_enable(gp2ap002->vio); in gp2ap002_probe()
578 gp2ap002->enabled = false; in gp2ap002_probe()
580 ret = devm_request_threaded_irq(dev, client->irq, NULL, in gp2ap002_probe()
587 gp2ap002->irq = client->irq; in gp2ap002_probe()
591 * measurement after power-on, do not shut it down unnecessarily. in gp2ap002_probe()
598 indio_dev->info = &gp2ap002_info; in gp2ap002_probe()
599 indio_dev->name = "gp2ap002"; in gp2ap002_probe()
600 indio_dev->channels = gp2ap002_channels; in gp2ap002_probe()
601 /* Skip light channel for the proximity-only sensor */ in gp2ap002_probe()
603 if (gp2ap002->is_gp2ap002s00f) in gp2ap002_probe()
604 num_chan--; in gp2ap002_probe()
605 indio_dev->num_channels = num_chan; in gp2ap002_probe()
606 indio_dev->modes = INDIO_DIRECT_MODE; in gp2ap002_probe()
620 regulator_disable(gp2ap002->vio); in gp2ap002_probe()
622 regulator_disable(gp2ap002->vdd); in gp2ap002_probe()
630 struct device *dev = &client->dev; in gp2ap002_remove()
636 regulator_disable(gp2ap002->vio); in gp2ap002_remove()
637 regulator_disable(gp2ap002->vdd); in gp2ap002_remove()
649 disable_irq(gp2ap002->irq); in gp2ap002_runtime_suspend()
652 ret = regmap_write(gp2ap002->map, GP2AP002_OPMOD, 0x00); in gp2ap002_runtime_suspend()
654 dev_err(gp2ap002->dev, "error setting up operation mode\n"); in gp2ap002_runtime_suspend()
661 regulator_disable(gp2ap002->vio); in gp2ap002_runtime_suspend()
662 regulator_disable(gp2ap002->vdd); in gp2ap002_runtime_suspend()
673 ret = regulator_enable(gp2ap002->vdd); in gp2ap002_runtime_resume()
678 ret = regulator_enable(gp2ap002->vio); in gp2ap002_runtime_resume()
688 dev_err(dev, "re-initialization failed\n"); in gp2ap002_runtime_resume()
692 /* Re-activate the IRQ */ in gp2ap002_runtime_resume()
693 enable_irq(gp2ap002->irq); in gp2ap002_runtime_resume()
731 MODULE_DESCRIPTION("GP2AP002 ambient light and proximity sensor driver");