diff options
Diffstat (limited to 'drivers/iio/light/tsl2772.c')
-rw-r--r-- | drivers/iio/light/tsl2772.c | 194 |
1 files changed, 191 insertions, 3 deletions
diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index df5b2a0da96c..83cece921843 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -20,6 +20,7 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/platform_data/tsl2772.h> +#include <linux/regulator/consumer.h> /* Cal defs */ #define PROX_STAT_CAL 0 @@ -107,6 +108,11 @@ #define TSL2772_ALS_GAIN_TRIM_MIN 250 #define TSL2772_ALS_GAIN_TRIM_MAX 4000 +#define TSL2772_MAX_PROX_LEDS 2 + +#define TSL2772_BOOT_MIN_SLEEP_TIME 10000 +#define TSL2772_BOOT_MAX_SLEEP_TIME 28000 + /* Device family members */ enum { tsl2571, @@ -118,7 +124,8 @@ enum { tsl2672, tmd2672, tsl2772, - tmd2772 + tmd2772, + apds9930, }; enum { @@ -141,11 +148,21 @@ struct tsl2772_chip_info { const struct iio_info *info; }; +static const int tsl2772_led_currents[][2] = { + { 100000, TSL2772_100_mA }, + { 50000, TSL2772_50_mA }, + { 25000, TSL2772_25_mA }, + { 13000, TSL2772_13_mA }, + { 0, 0 } +}; + struct tsl2772_chip { kernel_ulong_t id; struct mutex prox_mutex; struct mutex als_mutex; struct i2c_client *client; + struct regulator *vdd_supply; + struct regulator *vddio_supply; u16 prox_data; struct tsl2772_als_info als_cur_info; struct tsl2772_settings settings; @@ -197,6 +214,12 @@ static const struct tsl2772_lux tmd2x72_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { { 0, 0 }, }; +static const struct tsl2772_lux apds9930_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { + { 52000, 96824 }, + { 38792, 67132 }, + { 0, 0 }, +}; + static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = { [tsl2571] = tsl2x71_lux_table, [tsl2671] = tsl2x71_lux_table, @@ -208,6 +231,7 @@ static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = { [tmd2672] = tmd2x72_lux_table, [tsl2772] = tsl2x72_lux_table, [tmd2772] = tmd2x72_lux_table, + [apds9930] = apds9930_lux_table, }; static const struct tsl2772_settings tsl2772_default_settings = { @@ -258,6 +282,7 @@ static const int tsl2772_int_time_avail[][6] = { [tmd2672] = { 0, 2730, 0, 2730, 0, 699000 }, [tsl2772] = { 0, 2730, 0, 2730, 0, 699000 }, [tmd2772] = { 0, 2730, 0, 2730, 0, 699000 }, + [apds9930] = { 0, 2730, 0, 2730, 0, 699000 }, }; static int tsl2772_int_calibscale_avail[] = { 1, 8, 16, 120 }; @@ -283,7 +308,8 @@ static const u8 device_channel_config[] = { [tsl2672] = PRX2, [tmd2672] = PRX2, [tsl2772] = ALSPRX2, - [tmd2772] = ALSPRX2 + [tmd2772] = ALSPRX2, + [apds9930] = ALSPRX2, }; static int tsl2772_read_status(struct tsl2772_chip *chip) @@ -497,6 +523,7 @@ static int tsl2772_get_prox(struct iio_dev *indio_dev) case tmd2672: case tsl2772: case tmd2772: + case apds9930: if (!(ret & TSL2772_STA_PRX_VALID)) { ret = -EINVAL; goto prox_poll_err; @@ -515,6 +542,75 @@ prox_poll_err: return ret; } +static int tsl2772_read_prox_led_current(struct tsl2772_chip *chip) +{ + struct device_node *of_node = chip->client->dev.of_node; + int ret, tmp, i; + + ret = of_property_read_u32(of_node, "led-max-microamp", &tmp); + if (ret < 0) + return ret; + + for (i = 0; tsl2772_led_currents[i][0] != 0; i++) { + if (tmp == tsl2772_led_currents[i][0]) { + chip->settings.prox_power = tsl2772_led_currents[i][1]; + return 0; + } + } + + dev_err(&chip->client->dev, "Invalid value %d for led-max-microamp\n", + tmp); + + return -EINVAL; + +} + +static int tsl2772_read_prox_diodes(struct tsl2772_chip *chip) +{ + struct device_node *of_node = chip->client->dev.of_node; + int i, ret, num_leds, prox_diode_mask; + u32 leds[TSL2772_MAX_PROX_LEDS]; + + ret = of_property_count_u32_elems(of_node, "amstaos,proximity-diodes"); + if (ret < 0) + return ret; + + num_leds = ret; + if (num_leds > TSL2772_MAX_PROX_LEDS) + num_leds = TSL2772_MAX_PROX_LEDS; + + ret = of_property_read_u32_array(of_node, "amstaos,proximity-diodes", + leds, num_leds); + if (ret < 0) { + dev_err(&chip->client->dev, + "Invalid value for amstaos,proximity-diodes: %d.\n", + ret); + return ret; + } + + prox_diode_mask = 0; + for (i = 0; i < num_leds; i++) { + if (leds[i] == 0) + prox_diode_mask |= TSL2772_DIODE0; + else if (leds[i] == 1) + prox_diode_mask |= TSL2772_DIODE1; + else { + dev_err(&chip->client->dev, + "Invalid value %d in amstaos,proximity-diodes.\n", + leds[i]); + return -EINVAL; + } + } + + return 0; +} + +static void tsl2772_parse_dt(struct tsl2772_chip *chip) +{ + tsl2772_read_prox_led_current(chip); + tsl2772_read_prox_diodes(chip); +} + /** * tsl2772_defaults() - Populates the device nominal operating parameters * with those provided by a 'platform' data struct or @@ -541,6 +637,8 @@ static void tsl2772_defaults(struct tsl2772_chip *chip) memcpy(chip->tsl2772_device_lux, tsl2772_default_lux_table_group[chip->id], TSL2772_DEFAULT_TABLE_BYTES); + + tsl2772_parse_dt(chip); } /** @@ -595,6 +693,52 @@ static int tsl2772_als_calibrate(struct iio_dev *indio_dev) return ret; } +static void tsl2772_disable_regulators_action(void *_data) +{ + struct tsl2772_chip *chip = _data; + + regulator_disable(chip->vdd_supply); + regulator_disable(chip->vddio_supply); +} + +static int tsl2772_enable_regulator(struct tsl2772_chip *chip, + struct regulator *regulator) +{ + int ret; + + ret = regulator_enable(regulator); + if (ret < 0) { + dev_err(&chip->client->dev, "Failed to enable regulator: %d\n", + ret); + return ret; + } + + return 0; +} + +static struct regulator *tsl2772_get_regulator(struct tsl2772_chip *chip, + char *name) +{ + struct regulator *regulator; + int ret; + + regulator = devm_regulator_get(&chip->client->dev, name); + if (IS_ERR(regulator)) { + if (PTR_ERR(regulator) != -EPROBE_DEFER) + dev_err(&chip->client->dev, + "Failed to get %s regulator %d\n", + name, (int)PTR_ERR(regulator)); + + return regulator; + } + + ret = tsl2772_enable_regulator(chip, regulator); + if (ret < 0) + return ERR_PTR(ret); + + return regulator; +} + static int tsl2772_chip_on(struct iio_dev *indio_dev) { struct tsl2772_chip *chip = iio_priv(indio_dev); @@ -1260,6 +1404,7 @@ static int tsl2772_device_id_verif(int id, int target) case tmd2672: case tsl2772: case tmd2772: + case apds9930: return (id & 0xf0) == SWORDFISH_ID; } @@ -1652,6 +1797,27 @@ static int tsl2772_probe(struct i2c_client *clientp, chip->client = clientp; i2c_set_clientdata(clientp, indio_dev); + chip->vddio_supply = tsl2772_get_regulator(chip, "vddio"); + if (IS_ERR(chip->vddio_supply)) + return PTR_ERR(chip->vddio_supply); + + chip->vdd_supply = tsl2772_get_regulator(chip, "vdd"); + if (IS_ERR(chip->vdd_supply)) { + regulator_disable(chip->vddio_supply); + return PTR_ERR(chip->vdd_supply); + } + + ret = devm_add_action(&clientp->dev, tsl2772_disable_regulators_action, + chip); + if (ret < 0) { + tsl2772_disable_regulators_action(chip); + dev_err(&clientp->dev, "Failed to setup regulator cleanup action %d\n", + ret); + return ret; + } + + usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME); + ret = i2c_smbus_read_byte_data(chip->client, TSL2772_CMD_REG | TSL2772_CHIPID); if (ret < 0) @@ -1725,13 +1891,33 @@ static int tsl2772_probe(struct i2c_client *clientp, static int tsl2772_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2772_chip *chip = iio_priv(indio_dev); + int ret; + + ret = tsl2772_chip_off(indio_dev); + regulator_disable(chip->vdd_supply); + regulator_disable(chip->vddio_supply); - return tsl2772_chip_off(indio_dev); + return ret; } static int tsl2772_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2772_chip *chip = iio_priv(indio_dev); + int ret; + + ret = tsl2772_enable_regulator(chip, chip->vddio_supply); + if (ret < 0) + return ret; + + ret = tsl2772_enable_regulator(chip, chip->vdd_supply); + if (ret < 0) { + regulator_disable(chip->vddio_supply); + return ret; + } + + usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME); return tsl2772_chip_on(indio_dev); } @@ -1758,6 +1944,7 @@ static const struct i2c_device_id tsl2772_idtable[] = { { "tmd2672", tmd2672 }, { "tsl2772", tsl2772 }, { "tmd2772", tmd2772 }, + { "apds9930", apds9930}, {} }; @@ -1774,6 +1961,7 @@ static const struct of_device_id tsl2772_of_match[] = { { .compatible = "amstaos,tmd2672" }, { .compatible = "amstaos,tsl2772" }, { .compatible = "amstaos,tmd2772" }, + { .compatible = "avago,apds9930" }, {} }; MODULE_DEVICE_TABLE(of, tsl2772_of_match); |