.. | .. |
---|
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); |
---|