in light/gp2ap002.c [428:620]
static int gp2ap002_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct gp2ap002 *gp2ap002;
struct iio_dev *indio_dev;
struct device *dev = &client->dev;
enum iio_chan_type ch_type;
static const struct regmap_config config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = GP2AP002_CON,
};
struct regmap *regmap;
int num_chan;
const char *compat;
u8 val;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*gp2ap002));
if (!indio_dev)
return -ENOMEM;
i2c_set_clientdata(client, indio_dev);
gp2ap002 = iio_priv(indio_dev);
gp2ap002->dev = dev;
/*
* Check the device compatible like this makes it possible to use
* ACPI PRP0001 for registering the sensor using device tree
* properties.
*/
ret = device_property_read_string(dev, "compatible", &compat);
if (ret) {
dev_err(dev, "cannot check compatible\n");
return ret;
}
gp2ap002->is_gp2ap002s00f = !strcmp(compat, "sharp,gp2ap002s00f");
regmap = devm_regmap_init(dev, &gp2ap002_regmap_bus, dev, &config);
if (IS_ERR(regmap)) {
dev_err(dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap));
return PTR_ERR(regmap);
}
gp2ap002->map = regmap;
/*
* The hysteresis settings are coded into the device tree as values
* to be written into the hysteresis register. The datasheet defines
* modes "A", "B1" and "B2" with fixed values to be use but vendor
* code trees for actual devices are tweaking these values and refer to
* modes named things like "B1.5". To be able to support any devices,
* we allow passing an arbitrary hysteresis setting for "near" and
* "far".
*/
/* Check the device tree for the IR LED hysteresis */
ret = device_property_read_u8(dev, "sharp,proximity-far-hysteresis",
&val);
if (ret) {
dev_err(dev, "failed to obtain proximity far setting\n");
return ret;
}
dev_dbg(dev, "proximity far setting %02x\n", val);
gp2ap002->hys_far = val;
ret = device_property_read_u8(dev, "sharp,proximity-close-hysteresis",
&val);
if (ret) {
dev_err(dev, "failed to obtain proximity close setting\n");
return ret;
}
dev_dbg(dev, "proximity close setting %02x\n", val);
gp2ap002->hys_close = val;
/* The GP2AP002A00F has a light sensor too */
if (!gp2ap002->is_gp2ap002s00f) {
gp2ap002->alsout = devm_iio_channel_get(dev, "alsout");
if (IS_ERR(gp2ap002->alsout)) {
ret = PTR_ERR(gp2ap002->alsout);
ret = (ret == -ENODEV) ? -EPROBE_DEFER : ret;
return dev_err_probe(dev, ret, "failed to get ALSOUT ADC channel\n");
}
ret = iio_get_channel_type(gp2ap002->alsout, &ch_type);
if (ret < 0)
return ret;
if (ch_type != IIO_CURRENT) {
dev_err(dev,
"wrong type of IIO channel specified for ALSOUT\n");
return -EINVAL;
}
}
gp2ap002->vdd = devm_regulator_get(dev, "vdd");
if (IS_ERR(gp2ap002->vdd))
return dev_err_probe(dev, PTR_ERR(gp2ap002->vdd),
"failed to get VDD regulator\n");
gp2ap002->vio = devm_regulator_get(dev, "vio");
if (IS_ERR(gp2ap002->vio))
return dev_err_probe(dev, PTR_ERR(gp2ap002->vio),
"failed to get VIO regulator\n");
/* Operating voltage 2.4V .. 3.6V according to datasheet */
ret = regulator_set_voltage(gp2ap002->vdd, 2400000, 3600000);
if (ret) {
dev_err(dev, "failed to sett VDD voltage\n");
return ret;
}
/* VIO should be between 1.65V and VDD */
ret = regulator_get_voltage(gp2ap002->vdd);
if (ret < 0) {
dev_err(dev, "failed to get VDD voltage\n");
return ret;
}
ret = regulator_set_voltage(gp2ap002->vio, 1650000, ret);
if (ret) {
dev_err(dev, "failed to set VIO voltage\n");
return ret;
}
ret = regulator_enable(gp2ap002->vdd);
if (ret) {
dev_err(dev, "failed to enable VDD regulator\n");
return ret;
}
ret = regulator_enable(gp2ap002->vio);
if (ret) {
dev_err(dev, "failed to enable VIO regulator\n");
goto out_disable_vdd;
}
msleep(20);
/*
* Initialize the device and signal to runtime PM that now we are
* definitely up and using power.
*/
ret = gp2ap002_init(gp2ap002);
if (ret) {
dev_err(dev, "initialization failed\n");
goto out_disable_vio;
}
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
gp2ap002->enabled = false;
ret = devm_request_threaded_irq(dev, client->irq, NULL,
gp2ap002_prox_irq, IRQF_ONESHOT,
"gp2ap002", indio_dev);
if (ret) {
dev_err(dev, "unable to request IRQ\n");
goto out_put_pm;
}
gp2ap002->irq = client->irq;
/*
* As the device takes 20 ms + regulator delay to come up with a fresh
* measurement after power-on, do not shut it down unnecessarily.
* Set autosuspend to a one second.
*/
pm_runtime_set_autosuspend_delay(dev, 1000);
pm_runtime_use_autosuspend(dev);
pm_runtime_put(dev);
indio_dev->info = &gp2ap002_info;
indio_dev->name = "gp2ap002";
indio_dev->channels = gp2ap002_channels;
/* Skip light channel for the proximity-only sensor */
num_chan = ARRAY_SIZE(gp2ap002_channels);
if (gp2ap002->is_gp2ap002s00f)
num_chan--;
indio_dev->num_channels = num_chan;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_device_register(indio_dev);
if (ret)
goto out_disable_pm;
dev_dbg(dev, "Sharp GP2AP002 probed successfully\n");
return 0;
out_put_pm:
pm_runtime_put_noidle(dev);
out_disable_pm:
pm_runtime_disable(dev);
out_disable_vio:
regulator_disable(gp2ap002->vio);
out_disable_vdd:
regulator_disable(gp2ap002->vdd);
return ret;
}