al3320a.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * AL3320A - Dyna Image Ambient Light Sensor
  3. *
  4. * Copyright (c) 2014, Intel Corporation.
  5. *
  6. * This file is subject to the terms and conditions of version 2 of
  7. * the GNU General Public License. See the file COPYING in the main
  8. * directory of this archive for more details.
  9. *
  10. * IIO driver for AL3320A (7-bit I2C slave address 0x1C).
  11. *
  12. * TODO: interrupt support, thresholds
  13. *
  14. */
  15. #include <linux/module.h>
  16. #include <linux/init.h>
  17. #include <linux/i2c.h>
  18. #include <linux/iio/iio.h>
  19. #include <linux/iio/sysfs.h>
  20. #define AL3320A_DRV_NAME "al3320a"
  21. #define AL3320A_REG_CONFIG 0x00
  22. #define AL3320A_REG_STATUS 0x01
  23. #define AL3320A_REG_INT 0x02
  24. #define AL3320A_REG_WAIT 0x06
  25. #define AL3320A_REG_CONFIG_RANGE 0x07
  26. #define AL3320A_REG_PERSIST 0x08
  27. #define AL3320A_REG_MEAN_TIME 0x09
  28. #define AL3320A_REG_ADUMMY 0x0A
  29. #define AL3320A_REG_DATA_LOW 0x22
  30. #define AL3320A_REG_LOW_THRESH_LOW 0x30
  31. #define AL3320A_REG_LOW_THRESH_HIGH 0x31
  32. #define AL3320A_REG_HIGH_THRESH_LOW 0x32
  33. #define AL3320A_REG_HIGH_THRESH_HIGH 0x33
  34. #define AL3320A_CONFIG_DISABLE 0x00
  35. #define AL3320A_CONFIG_ENABLE 0x01
  36. #define AL3320A_GAIN_SHIFT 1
  37. #define AL3320A_GAIN_MASK (BIT(2) | BIT(1))
  38. /* chip params default values */
  39. #define AL3320A_DEFAULT_MEAN_TIME 4
  40. #define AL3320A_DEFAULT_WAIT_TIME 0 /* no waiting */
  41. #define AL3320A_SCALE_AVAILABLE "0.512 0.128 0.032 0.01"
  42. enum al3320a_range {
  43. AL3320A_RANGE_1, /* 33.28 Klx */
  44. AL3320A_RANGE_2, /* 8.32 Klx */
  45. AL3320A_RANGE_3, /* 2.08 Klx */
  46. AL3320A_RANGE_4 /* 0.65 Klx */
  47. };
  48. static const int al3320a_scales[][2] = {
  49. {0, 512000}, {0, 128000}, {0, 32000}, {0, 10000}
  50. };
  51. struct al3320a_data {
  52. struct i2c_client *client;
  53. };
  54. static const struct iio_chan_spec al3320a_channels[] = {
  55. {
  56. .type = IIO_LIGHT,
  57. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  58. BIT(IIO_CHAN_INFO_SCALE),
  59. }
  60. };
  61. static IIO_CONST_ATTR(in_illuminance_scale_available, AL3320A_SCALE_AVAILABLE);
  62. static struct attribute *al3320a_attributes[] = {
  63. &iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
  64. NULL,
  65. };
  66. static const struct attribute_group al3320a_attribute_group = {
  67. .attrs = al3320a_attributes,
  68. };
  69. static int al3320a_init(struct al3320a_data *data)
  70. {
  71. int ret;
  72. /* power on */
  73. ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_CONFIG,
  74. AL3320A_CONFIG_ENABLE);
  75. if (ret < 0)
  76. return ret;
  77. ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_CONFIG_RANGE,
  78. AL3320A_RANGE_3 << AL3320A_GAIN_SHIFT);
  79. if (ret < 0)
  80. return ret;
  81. ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_MEAN_TIME,
  82. AL3320A_DEFAULT_MEAN_TIME);
  83. if (ret < 0)
  84. return ret;
  85. ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_WAIT,
  86. AL3320A_DEFAULT_WAIT_TIME);
  87. if (ret < 0)
  88. return ret;
  89. return 0;
  90. }
  91. static int al3320a_read_raw(struct iio_dev *indio_dev,
  92. struct iio_chan_spec const *chan, int *val,
  93. int *val2, long mask)
  94. {
  95. struct al3320a_data *data = iio_priv(indio_dev);
  96. int ret;
  97. switch (mask) {
  98. case IIO_CHAN_INFO_RAW:
  99. /*
  100. * ALS ADC value is stored in two adjacent registers:
  101. * - low byte of output is stored at AL3320A_REG_DATA_LOW
  102. * - high byte of output is stored at AL3320A_REG_DATA_LOW + 1
  103. */
  104. ret = i2c_smbus_read_word_data(data->client,
  105. AL3320A_REG_DATA_LOW);
  106. if (ret < 0)
  107. return ret;
  108. *val = ret;
  109. return IIO_VAL_INT;
  110. case IIO_CHAN_INFO_SCALE:
  111. ret = i2c_smbus_read_byte_data(data->client,
  112. AL3320A_REG_CONFIG_RANGE);
  113. if (ret < 0)
  114. return ret;
  115. ret = (ret & AL3320A_GAIN_MASK) >> AL3320A_GAIN_SHIFT;
  116. *val = al3320a_scales[ret][0];
  117. *val2 = al3320a_scales[ret][1];
  118. return IIO_VAL_INT_PLUS_MICRO;
  119. }
  120. return -EINVAL;
  121. }
  122. static int al3320a_write_raw(struct iio_dev *indio_dev,
  123. struct iio_chan_spec const *chan, int val,
  124. int val2, long mask)
  125. {
  126. struct al3320a_data *data = iio_priv(indio_dev);
  127. int i;
  128. switch (mask) {
  129. case IIO_CHAN_INFO_SCALE:
  130. for (i = 0; i < ARRAY_SIZE(al3320a_scales); i++) {
  131. if (val == al3320a_scales[i][0] &&
  132. val2 == al3320a_scales[i][1])
  133. return i2c_smbus_write_byte_data(data->client,
  134. AL3320A_REG_CONFIG_RANGE,
  135. i << AL3320A_GAIN_SHIFT);
  136. }
  137. break;
  138. }
  139. return -EINVAL;
  140. }
  141. static const struct iio_info al3320a_info = {
  142. .read_raw = al3320a_read_raw,
  143. .write_raw = al3320a_write_raw,
  144. .attrs = &al3320a_attribute_group,
  145. };
  146. static int al3320a_probe(struct i2c_client *client,
  147. const struct i2c_device_id *id)
  148. {
  149. struct al3320a_data *data;
  150. struct iio_dev *indio_dev;
  151. int ret;
  152. indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
  153. if (!indio_dev)
  154. return -ENOMEM;
  155. data = iio_priv(indio_dev);
  156. i2c_set_clientdata(client, indio_dev);
  157. data->client = client;
  158. indio_dev->dev.parent = &client->dev;
  159. indio_dev->info = &al3320a_info;
  160. indio_dev->name = AL3320A_DRV_NAME;
  161. indio_dev->channels = al3320a_channels;
  162. indio_dev->num_channels = ARRAY_SIZE(al3320a_channels);
  163. indio_dev->modes = INDIO_DIRECT_MODE;
  164. ret = al3320a_init(data);
  165. if (ret < 0) {
  166. dev_err(&client->dev, "al3320a chip init failed\n");
  167. return ret;
  168. }
  169. return devm_iio_device_register(&client->dev, indio_dev);
  170. }
  171. static int al3320a_remove(struct i2c_client *client)
  172. {
  173. return i2c_smbus_write_byte_data(client, AL3320A_REG_CONFIG,
  174. AL3320A_CONFIG_DISABLE);
  175. }
  176. static const struct i2c_device_id al3320a_id[] = {
  177. {"al3320a", 0},
  178. {}
  179. };
  180. MODULE_DEVICE_TABLE(i2c, al3320a_id);
  181. static struct i2c_driver al3320a_driver = {
  182. .driver = {
  183. .name = AL3320A_DRV_NAME,
  184. },
  185. .probe = al3320a_probe,
  186. .remove = al3320a_remove,
  187. .id_table = al3320a_id,
  188. };
  189. module_i2c_driver(al3320a_driver);
  190. MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
  191. MODULE_DESCRIPTION("AL3320A Ambient Light Sensor driver");
  192. MODULE_LICENSE("GPL v2");