| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * A iio driver for the light sensor ISL 29018/29023/29035. |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 5 | 6 | * sensing and infrared sensing. |
|---|
| 6 | 7 | * |
|---|
| 7 | 8 | * Copyright (c) 2010, NVIDIA Corporation. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 10 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 11 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 12 | | - * (at your option) any later version. |
|---|
| 13 | | - * |
|---|
| 14 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 15 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 16 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 17 | | - * more details. |
|---|
| 18 | 9 | */ |
|---|
| 19 | 10 | |
|---|
| 20 | 11 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 23 | 14 | #include <linux/mutex.h> |
|---|
| 24 | 15 | #include <linux/delay.h> |
|---|
| 25 | 16 | #include <linux/regmap.h> |
|---|
| 17 | +#include <linux/regulator/consumer.h> |
|---|
| 26 | 18 | #include <linux/slab.h> |
|---|
| 27 | 19 | #include <linux/iio/iio.h> |
|---|
| 28 | 20 | #include <linux/iio/sysfs.h> |
|---|
| .. | .. |
|---|
| 95 | 87 | struct isl29018_scale scale; |
|---|
| 96 | 88 | int prox_scheme; |
|---|
| 97 | 89 | bool suspended; |
|---|
| 90 | + struct regulator *vcc_reg; |
|---|
| 98 | 91 | }; |
|---|
| 99 | 92 | |
|---|
| 100 | 93 | static int isl29018_set_integration_time(struct isl29018_chip *chip, |
|---|
| .. | .. |
|---|
| 708 | 701 | return dev_name(dev); |
|---|
| 709 | 702 | } |
|---|
| 710 | 703 | |
|---|
| 704 | +static void isl29018_disable_regulator_action(void *_data) |
|---|
| 705 | +{ |
|---|
| 706 | + struct isl29018_chip *chip = _data; |
|---|
| 707 | + int err; |
|---|
| 708 | + |
|---|
| 709 | + err = regulator_disable(chip->vcc_reg); |
|---|
| 710 | + if (err) |
|---|
| 711 | + pr_err("failed to disable isl29018's VCC regulator!\n"); |
|---|
| 712 | +} |
|---|
| 713 | + |
|---|
| 711 | 714 | static int isl29018_probe(struct i2c_client *client, |
|---|
| 712 | 715 | const struct i2c_device_id *id) |
|---|
| 713 | 716 | { |
|---|
| .. | .. |
|---|
| 742 | 745 | chip->scale = isl29018_scales[chip->int_time][0]; |
|---|
| 743 | 746 | chip->suspended = false; |
|---|
| 744 | 747 | |
|---|
| 748 | + chip->vcc_reg = devm_regulator_get(&client->dev, "vcc"); |
|---|
| 749 | + if (IS_ERR(chip->vcc_reg)) |
|---|
| 750 | + return dev_err_probe(&client->dev, PTR_ERR(chip->vcc_reg), |
|---|
| 751 | + "failed to get VCC regulator!\n"); |
|---|
| 752 | + |
|---|
| 753 | + err = regulator_enable(chip->vcc_reg); |
|---|
| 754 | + if (err) { |
|---|
| 755 | + dev_err(&client->dev, "failed to enable VCC regulator!\n"); |
|---|
| 756 | + return err; |
|---|
| 757 | + } |
|---|
| 758 | + |
|---|
| 759 | + err = devm_add_action_or_reset(&client->dev, isl29018_disable_regulator_action, |
|---|
| 760 | + chip); |
|---|
| 761 | + if (err) { |
|---|
| 762 | + dev_err(&client->dev, "failed to setup regulator cleanup action!\n"); |
|---|
| 763 | + return err; |
|---|
| 764 | + } |
|---|
| 765 | + |
|---|
| 745 | 766 | chip->regmap = devm_regmap_init_i2c(client, |
|---|
| 746 | 767 | isl29018_chip_info_tbl[dev_id].regmap_cfg); |
|---|
| 747 | 768 | if (IS_ERR(chip->regmap)) { |
|---|
| .. | .. |
|---|
| 758 | 779 | indio_dev->channels = isl29018_chip_info_tbl[dev_id].channels; |
|---|
| 759 | 780 | indio_dev->num_channels = isl29018_chip_info_tbl[dev_id].num_channels; |
|---|
| 760 | 781 | indio_dev->name = name; |
|---|
| 761 | | - indio_dev->dev.parent = &client->dev; |
|---|
| 762 | 782 | indio_dev->modes = INDIO_DIRECT_MODE; |
|---|
| 763 | 783 | |
|---|
| 764 | 784 | return devm_iio_device_register(&client->dev, indio_dev); |
|---|
| .. | .. |
|---|
| 768 | 788 | static int isl29018_suspend(struct device *dev) |
|---|
| 769 | 789 | { |
|---|
| 770 | 790 | struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev)); |
|---|
| 791 | + int ret; |
|---|
| 771 | 792 | |
|---|
| 772 | 793 | mutex_lock(&chip->lock); |
|---|
| 773 | 794 | |
|---|
| .. | .. |
|---|
| 777 | 798 | * So we do not have much to do here. |
|---|
| 778 | 799 | */ |
|---|
| 779 | 800 | chip->suspended = true; |
|---|
| 801 | + ret = regulator_disable(chip->vcc_reg); |
|---|
| 802 | + if (ret) |
|---|
| 803 | + dev_err(dev, "failed to disable VCC regulator\n"); |
|---|
| 780 | 804 | |
|---|
| 781 | 805 | mutex_unlock(&chip->lock); |
|---|
| 782 | 806 | |
|---|
| 783 | | - return 0; |
|---|
| 807 | + return ret; |
|---|
| 784 | 808 | } |
|---|
| 785 | 809 | |
|---|
| 786 | 810 | static int isl29018_resume(struct device *dev) |
|---|
| .. | .. |
|---|
| 790 | 814 | |
|---|
| 791 | 815 | mutex_lock(&chip->lock); |
|---|
| 792 | 816 | |
|---|
| 817 | + err = regulator_enable(chip->vcc_reg); |
|---|
| 818 | + if (err) { |
|---|
| 819 | + dev_err(dev, "failed to enable VCC regulator\n"); |
|---|
| 820 | + mutex_unlock(&chip->lock); |
|---|
| 821 | + return err; |
|---|
| 822 | + } |
|---|
| 823 | + |
|---|
| 793 | 824 | err = isl29018_chip_init(chip); |
|---|
| 794 | 825 | if (!err) |
|---|
| 795 | 826 | chip->suspended = false; |
|---|