| .. | .. |
|---|
| 20 | 20 | #include <linux/iio/iio.h> |
|---|
| 21 | 21 | #include <linux/iio/sysfs.h> |
|---|
| 22 | 22 | #include <linux/platform_data/tsl2772.h> |
|---|
| 23 | +#include <linux/regulator/consumer.h> |
|---|
| 23 | 24 | |
|---|
| 24 | 25 | /* Cal defs */ |
|---|
| 25 | 26 | #define PROX_STAT_CAL 0 |
|---|
| .. | .. |
|---|
| 107 | 108 | #define TSL2772_ALS_GAIN_TRIM_MIN 250 |
|---|
| 108 | 109 | #define TSL2772_ALS_GAIN_TRIM_MAX 4000 |
|---|
| 109 | 110 | |
|---|
| 111 | +#define TSL2772_MAX_PROX_LEDS 2 |
|---|
| 112 | + |
|---|
| 113 | +#define TSL2772_BOOT_MIN_SLEEP_TIME 10000 |
|---|
| 114 | +#define TSL2772_BOOT_MAX_SLEEP_TIME 28000 |
|---|
| 115 | + |
|---|
| 110 | 116 | /* Device family members */ |
|---|
| 111 | 117 | enum { |
|---|
| 112 | 118 | tsl2571, |
|---|
| .. | .. |
|---|
| 118 | 124 | tsl2672, |
|---|
| 119 | 125 | tmd2672, |
|---|
| 120 | 126 | tsl2772, |
|---|
| 121 | | - tmd2772 |
|---|
| 127 | + tmd2772, |
|---|
| 128 | + apds9930, |
|---|
| 122 | 129 | }; |
|---|
| 123 | 130 | |
|---|
| 124 | 131 | enum { |
|---|
| 125 | 132 | TSL2772_CHIP_UNKNOWN = 0, |
|---|
| 126 | 133 | TSL2772_CHIP_WORKING = 1, |
|---|
| 127 | 134 | TSL2772_CHIP_SUSPENDED = 2 |
|---|
| 135 | +}; |
|---|
| 136 | + |
|---|
| 137 | +enum { |
|---|
| 138 | + TSL2772_SUPPLY_VDD = 0, |
|---|
| 139 | + TSL2772_SUPPLY_VDDIO = 1, |
|---|
| 140 | + TSL2772_NUM_SUPPLIES = 2 |
|---|
| 128 | 141 | }; |
|---|
| 129 | 142 | |
|---|
| 130 | 143 | /* Per-device data */ |
|---|
| .. | .. |
|---|
| 141 | 154 | const struct iio_info *info; |
|---|
| 142 | 155 | }; |
|---|
| 143 | 156 | |
|---|
| 157 | +static const int tsl2772_led_currents[][2] = { |
|---|
| 158 | + { 100000, TSL2772_100_mA }, |
|---|
| 159 | + { 50000, TSL2772_50_mA }, |
|---|
| 160 | + { 25000, TSL2772_25_mA }, |
|---|
| 161 | + { 13000, TSL2772_13_mA }, |
|---|
| 162 | + { 0, 0 } |
|---|
| 163 | +}; |
|---|
| 164 | + |
|---|
| 144 | 165 | struct tsl2772_chip { |
|---|
| 145 | 166 | kernel_ulong_t id; |
|---|
| 146 | 167 | struct mutex prox_mutex; |
|---|
| 147 | 168 | struct mutex als_mutex; |
|---|
| 148 | 169 | struct i2c_client *client; |
|---|
| 170 | + struct regulator_bulk_data supplies[TSL2772_NUM_SUPPLIES]; |
|---|
| 149 | 171 | u16 prox_data; |
|---|
| 150 | 172 | struct tsl2772_als_info als_cur_info; |
|---|
| 151 | 173 | struct tsl2772_settings settings; |
|---|
| .. | .. |
|---|
| 197 | 219 | { 0, 0 }, |
|---|
| 198 | 220 | }; |
|---|
| 199 | 221 | |
|---|
| 222 | +static const struct tsl2772_lux apds9930_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { |
|---|
| 223 | + { 52000, 96824 }, |
|---|
| 224 | + { 38792, 67132 }, |
|---|
| 225 | + { 0, 0 }, |
|---|
| 226 | +}; |
|---|
| 227 | + |
|---|
| 200 | 228 | static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = { |
|---|
| 201 | 229 | [tsl2571] = tsl2x71_lux_table, |
|---|
| 202 | 230 | [tsl2671] = tsl2x71_lux_table, |
|---|
| .. | .. |
|---|
| 208 | 236 | [tmd2672] = tmd2x72_lux_table, |
|---|
| 209 | 237 | [tsl2772] = tsl2x72_lux_table, |
|---|
| 210 | 238 | [tmd2772] = tmd2x72_lux_table, |
|---|
| 239 | + [apds9930] = apds9930_lux_table, |
|---|
| 211 | 240 | }; |
|---|
| 212 | 241 | |
|---|
| 213 | 242 | static const struct tsl2772_settings tsl2772_default_settings = { |
|---|
| .. | .. |
|---|
| 258 | 287 | [tmd2672] = { 0, 2730, 0, 2730, 0, 699000 }, |
|---|
| 259 | 288 | [tsl2772] = { 0, 2730, 0, 2730, 0, 699000 }, |
|---|
| 260 | 289 | [tmd2772] = { 0, 2730, 0, 2730, 0, 699000 }, |
|---|
| 290 | + [apds9930] = { 0, 2730, 0, 2730, 0, 699000 }, |
|---|
| 261 | 291 | }; |
|---|
| 262 | 292 | |
|---|
| 263 | 293 | static int tsl2772_int_calibscale_avail[] = { 1, 8, 16, 120 }; |
|---|
| .. | .. |
|---|
| 283 | 313 | [tsl2672] = PRX2, |
|---|
| 284 | 314 | [tmd2672] = PRX2, |
|---|
| 285 | 315 | [tsl2772] = ALSPRX2, |
|---|
| 286 | | - [tmd2772] = ALSPRX2 |
|---|
| 316 | + [tmd2772] = ALSPRX2, |
|---|
| 317 | + [apds9930] = ALSPRX2, |
|---|
| 287 | 318 | }; |
|---|
| 288 | 319 | |
|---|
| 289 | 320 | static int tsl2772_read_status(struct tsl2772_chip *chip) |
|---|
| .. | .. |
|---|
| 497 | 528 | case tmd2672: |
|---|
| 498 | 529 | case tsl2772: |
|---|
| 499 | 530 | case tmd2772: |
|---|
| 531 | + case apds9930: |
|---|
| 500 | 532 | if (!(ret & TSL2772_STA_PRX_VALID)) { |
|---|
| 501 | 533 | ret = -EINVAL; |
|---|
| 502 | 534 | goto prox_poll_err; |
|---|
| .. | .. |
|---|
| 513 | 545 | mutex_unlock(&chip->prox_mutex); |
|---|
| 514 | 546 | |
|---|
| 515 | 547 | return ret; |
|---|
| 548 | +} |
|---|
| 549 | + |
|---|
| 550 | +static int tsl2772_read_prox_led_current(struct tsl2772_chip *chip) |
|---|
| 551 | +{ |
|---|
| 552 | + struct device_node *of_node = chip->client->dev.of_node; |
|---|
| 553 | + int ret, tmp, i; |
|---|
| 554 | + |
|---|
| 555 | + ret = of_property_read_u32(of_node, "led-max-microamp", &tmp); |
|---|
| 556 | + if (ret < 0) |
|---|
| 557 | + return ret; |
|---|
| 558 | + |
|---|
| 559 | + for (i = 0; tsl2772_led_currents[i][0] != 0; i++) { |
|---|
| 560 | + if (tmp == tsl2772_led_currents[i][0]) { |
|---|
| 561 | + chip->settings.prox_power = tsl2772_led_currents[i][1]; |
|---|
| 562 | + return 0; |
|---|
| 563 | + } |
|---|
| 564 | + } |
|---|
| 565 | + |
|---|
| 566 | + dev_err(&chip->client->dev, "Invalid value %d for led-max-microamp\n", |
|---|
| 567 | + tmp); |
|---|
| 568 | + |
|---|
| 569 | + return -EINVAL; |
|---|
| 570 | + |
|---|
| 571 | +} |
|---|
| 572 | + |
|---|
| 573 | +static int tsl2772_read_prox_diodes(struct tsl2772_chip *chip) |
|---|
| 574 | +{ |
|---|
| 575 | + struct device_node *of_node = chip->client->dev.of_node; |
|---|
| 576 | + int i, ret, num_leds, prox_diode_mask; |
|---|
| 577 | + u32 leds[TSL2772_MAX_PROX_LEDS]; |
|---|
| 578 | + |
|---|
| 579 | + ret = of_property_count_u32_elems(of_node, "amstaos,proximity-diodes"); |
|---|
| 580 | + if (ret < 0) |
|---|
| 581 | + return ret; |
|---|
| 582 | + |
|---|
| 583 | + num_leds = ret; |
|---|
| 584 | + if (num_leds > TSL2772_MAX_PROX_LEDS) |
|---|
| 585 | + num_leds = TSL2772_MAX_PROX_LEDS; |
|---|
| 586 | + |
|---|
| 587 | + ret = of_property_read_u32_array(of_node, "amstaos,proximity-diodes", |
|---|
| 588 | + leds, num_leds); |
|---|
| 589 | + if (ret < 0) { |
|---|
| 590 | + dev_err(&chip->client->dev, |
|---|
| 591 | + "Invalid value for amstaos,proximity-diodes: %d.\n", |
|---|
| 592 | + ret); |
|---|
| 593 | + return ret; |
|---|
| 594 | + } |
|---|
| 595 | + |
|---|
| 596 | + prox_diode_mask = 0; |
|---|
| 597 | + for (i = 0; i < num_leds; i++) { |
|---|
| 598 | + if (leds[i] == 0) |
|---|
| 599 | + prox_diode_mask |= TSL2772_DIODE0; |
|---|
| 600 | + else if (leds[i] == 1) |
|---|
| 601 | + prox_diode_mask |= TSL2772_DIODE1; |
|---|
| 602 | + else { |
|---|
| 603 | + dev_err(&chip->client->dev, |
|---|
| 604 | + "Invalid value %d in amstaos,proximity-diodes.\n", |
|---|
| 605 | + leds[i]); |
|---|
| 606 | + return -EINVAL; |
|---|
| 607 | + } |
|---|
| 608 | + } |
|---|
| 609 | + chip->settings.prox_diode = prox_diode_mask; |
|---|
| 610 | + |
|---|
| 611 | + return 0; |
|---|
| 612 | +} |
|---|
| 613 | + |
|---|
| 614 | +static void tsl2772_parse_dt(struct tsl2772_chip *chip) |
|---|
| 615 | +{ |
|---|
| 616 | + tsl2772_read_prox_led_current(chip); |
|---|
| 617 | + tsl2772_read_prox_diodes(chip); |
|---|
| 516 | 618 | } |
|---|
| 517 | 619 | |
|---|
| 518 | 620 | /** |
|---|
| .. | .. |
|---|
| 541 | 643 | memcpy(chip->tsl2772_device_lux, |
|---|
| 542 | 644 | tsl2772_default_lux_table_group[chip->id], |
|---|
| 543 | 645 | TSL2772_DEFAULT_TABLE_BYTES); |
|---|
| 646 | + |
|---|
| 647 | + tsl2772_parse_dt(chip); |
|---|
| 544 | 648 | } |
|---|
| 545 | 649 | |
|---|
| 546 | 650 | /** |
|---|
| .. | .. |
|---|
| 593 | 697 | chip->settings.als_gain_trim = ret; |
|---|
| 594 | 698 | |
|---|
| 595 | 699 | return ret; |
|---|
| 700 | +} |
|---|
| 701 | + |
|---|
| 702 | +static void tsl2772_disable_regulators_action(void *_data) |
|---|
| 703 | +{ |
|---|
| 704 | + struct tsl2772_chip *chip = _data; |
|---|
| 705 | + |
|---|
| 706 | + regulator_bulk_disable(ARRAY_SIZE(chip->supplies), chip->supplies); |
|---|
| 596 | 707 | } |
|---|
| 597 | 708 | |
|---|
| 598 | 709 | static int tsl2772_chip_on(struct iio_dev *indio_dev) |
|---|
| .. | .. |
|---|
| 822 | 933 | { |
|---|
| 823 | 934 | struct tsl2772_chip *chip = iio_priv(dev_to_iio_dev(dev)); |
|---|
| 824 | 935 | |
|---|
| 825 | | - return snprintf(buf, PAGE_SIZE, "%d\n", chip->settings.als_cal_target); |
|---|
| 936 | + return scnprintf(buf, PAGE_SIZE, "%d\n", chip->settings.als_cal_target); |
|---|
| 826 | 937 | } |
|---|
| 827 | 938 | |
|---|
| 828 | 939 | static ssize_t in_illuminance0_target_input_store(struct device *dev, |
|---|
| .. | .. |
|---|
| 876 | 987 | int offset = 0; |
|---|
| 877 | 988 | |
|---|
| 878 | 989 | while (i < TSL2772_MAX_LUX_TABLE_SIZE) { |
|---|
| 879 | | - offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,", |
|---|
| 990 | + offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%u,%u,", |
|---|
| 880 | 991 | chip->tsl2772_device_lux[i].ch0, |
|---|
| 881 | 992 | chip->tsl2772_device_lux[i].ch1); |
|---|
| 882 | 993 | if (chip->tsl2772_device_lux[i].ch0 == 0) { |
|---|
| .. | .. |
|---|
| 890 | 1001 | i++; |
|---|
| 891 | 1002 | } |
|---|
| 892 | 1003 | |
|---|
| 893 | | - offset += snprintf(buf + offset, PAGE_SIZE, "\n"); |
|---|
| 1004 | + offset += scnprintf(buf + offset, PAGE_SIZE - offset, "\n"); |
|---|
| 894 | 1005 | return offset; |
|---|
| 895 | 1006 | } |
|---|
| 896 | 1007 | |
|---|
| .. | .. |
|---|
| 1267 | 1378 | case tmd2672: |
|---|
| 1268 | 1379 | case tsl2772: |
|---|
| 1269 | 1380 | case tmd2772: |
|---|
| 1381 | + case apds9930: |
|---|
| 1270 | 1382 | return (id & 0xf0) == SWORDFISH_ID; |
|---|
| 1271 | 1383 | } |
|---|
| 1272 | 1384 | |
|---|
| .. | .. |
|---|
| 1659 | 1771 | chip->client = clientp; |
|---|
| 1660 | 1772 | i2c_set_clientdata(clientp, indio_dev); |
|---|
| 1661 | 1773 | |
|---|
| 1774 | + chip->supplies[TSL2772_SUPPLY_VDD].supply = "vdd"; |
|---|
| 1775 | + chip->supplies[TSL2772_SUPPLY_VDDIO].supply = "vddio"; |
|---|
| 1776 | + |
|---|
| 1777 | + ret = devm_regulator_bulk_get(&clientp->dev, |
|---|
| 1778 | + ARRAY_SIZE(chip->supplies), |
|---|
| 1779 | + chip->supplies); |
|---|
| 1780 | + if (ret < 0) |
|---|
| 1781 | + return dev_err_probe(&clientp->dev, ret, "Failed to get regulators\n"); |
|---|
| 1782 | + |
|---|
| 1783 | + ret = regulator_bulk_enable(ARRAY_SIZE(chip->supplies), chip->supplies); |
|---|
| 1784 | + if (ret < 0) { |
|---|
| 1785 | + dev_err(&clientp->dev, "Failed to enable regulators: %d\n", |
|---|
| 1786 | + ret); |
|---|
| 1787 | + return ret; |
|---|
| 1788 | + } |
|---|
| 1789 | + |
|---|
| 1790 | + ret = devm_add_action_or_reset(&clientp->dev, |
|---|
| 1791 | + tsl2772_disable_regulators_action, |
|---|
| 1792 | + chip); |
|---|
| 1793 | + if (ret < 0) { |
|---|
| 1794 | + dev_err(&clientp->dev, "Failed to setup regulator cleanup action %d\n", |
|---|
| 1795 | + ret); |
|---|
| 1796 | + return ret; |
|---|
| 1797 | + } |
|---|
| 1798 | + |
|---|
| 1799 | + usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME); |
|---|
| 1800 | + |
|---|
| 1662 | 1801 | ret = i2c_smbus_read_byte_data(chip->client, |
|---|
| 1663 | 1802 | TSL2772_CMD_REG | TSL2772_CHIPID); |
|---|
| 1664 | 1803 | if (ret < 0) |
|---|
| .. | .. |
|---|
| 1689 | 1828 | &tsl2772_chip_info_tbl[device_channel_config[id->driver_data]]; |
|---|
| 1690 | 1829 | |
|---|
| 1691 | 1830 | indio_dev->info = chip->chip_info->info; |
|---|
| 1692 | | - indio_dev->dev.parent = &clientp->dev; |
|---|
| 1693 | 1831 | indio_dev->modes = INDIO_DIRECT_MODE; |
|---|
| 1694 | 1832 | indio_dev->name = chip->client->name; |
|---|
| 1695 | 1833 | indio_dev->num_channels = chip->chip_info->chan_table_elements; |
|---|
| .. | .. |
|---|
| 1724 | 1862 | if (ret < 0) |
|---|
| 1725 | 1863 | return ret; |
|---|
| 1726 | 1864 | |
|---|
| 1727 | | - ret = iio_device_register(indio_dev); |
|---|
| 1728 | | - if (ret) { |
|---|
| 1729 | | - dev_err(&clientp->dev, |
|---|
| 1730 | | - "%s: iio registration failed\n", __func__); |
|---|
| 1731 | | - return ret; |
|---|
| 1732 | | - } |
|---|
| 1733 | | - |
|---|
| 1734 | | - return 0; |
|---|
| 1865 | + return devm_iio_device_register(&clientp->dev, indio_dev); |
|---|
| 1735 | 1866 | } |
|---|
| 1736 | 1867 | |
|---|
| 1737 | 1868 | static int tsl2772_suspend(struct device *dev) |
|---|
| 1738 | 1869 | { |
|---|
| 1739 | 1870 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
|---|
| 1871 | + struct tsl2772_chip *chip = iio_priv(indio_dev); |
|---|
| 1872 | + int ret; |
|---|
| 1740 | 1873 | |
|---|
| 1741 | | - return tsl2772_chip_off(indio_dev); |
|---|
| 1874 | + ret = tsl2772_chip_off(indio_dev); |
|---|
| 1875 | + regulator_bulk_disable(ARRAY_SIZE(chip->supplies), chip->supplies); |
|---|
| 1876 | + |
|---|
| 1877 | + return ret; |
|---|
| 1742 | 1878 | } |
|---|
| 1743 | 1879 | |
|---|
| 1744 | 1880 | static int tsl2772_resume(struct device *dev) |
|---|
| 1745 | 1881 | { |
|---|
| 1746 | 1882 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
|---|
| 1883 | + struct tsl2772_chip *chip = iio_priv(indio_dev); |
|---|
| 1884 | + int ret; |
|---|
| 1885 | + |
|---|
| 1886 | + ret = regulator_bulk_enable(ARRAY_SIZE(chip->supplies), chip->supplies); |
|---|
| 1887 | + if (ret < 0) |
|---|
| 1888 | + return ret; |
|---|
| 1889 | + |
|---|
| 1890 | + usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME); |
|---|
| 1747 | 1891 | |
|---|
| 1748 | 1892 | return tsl2772_chip_on(indio_dev); |
|---|
| 1749 | | -} |
|---|
| 1750 | | - |
|---|
| 1751 | | -static int tsl2772_remove(struct i2c_client *client) |
|---|
| 1752 | | -{ |
|---|
| 1753 | | - struct iio_dev *indio_dev = i2c_get_clientdata(client); |
|---|
| 1754 | | - |
|---|
| 1755 | | - iio_device_unregister(indio_dev); |
|---|
| 1756 | | - |
|---|
| 1757 | | - return 0; |
|---|
| 1758 | 1893 | } |
|---|
| 1759 | 1894 | |
|---|
| 1760 | 1895 | static const struct i2c_device_id tsl2772_idtable[] = { |
|---|
| .. | .. |
|---|
| 1768 | 1903 | { "tmd2672", tmd2672 }, |
|---|
| 1769 | 1904 | { "tsl2772", tsl2772 }, |
|---|
| 1770 | 1905 | { "tmd2772", tmd2772 }, |
|---|
| 1906 | + { "apds9930", apds9930}, |
|---|
| 1771 | 1907 | {} |
|---|
| 1772 | 1908 | }; |
|---|
| 1773 | 1909 | |
|---|
| .. | .. |
|---|
| 1784 | 1920 | { .compatible = "amstaos,tmd2672" }, |
|---|
| 1785 | 1921 | { .compatible = "amstaos,tsl2772" }, |
|---|
| 1786 | 1922 | { .compatible = "amstaos,tmd2772" }, |
|---|
| 1923 | + { .compatible = "avago,apds9930" }, |
|---|
| 1787 | 1924 | {} |
|---|
| 1788 | 1925 | }; |
|---|
| 1789 | 1926 | MODULE_DEVICE_TABLE(of, tsl2772_of_match); |
|---|
| .. | .. |
|---|
| 1801 | 1938 | }, |
|---|
| 1802 | 1939 | .id_table = tsl2772_idtable, |
|---|
| 1803 | 1940 | .probe = tsl2772_probe, |
|---|
| 1804 | | - .remove = tsl2772_remove, |
|---|
| 1805 | 1941 | }; |
|---|
| 1806 | 1942 | |
|---|
| 1807 | 1943 | module_i2c_driver(tsl2772_driver); |
|---|