0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/module.h>
0013 #include <linux/mod_devicetable.h>
0014 #include <linux/iio/iio.h>
0015 #include <linux/iio/sysfs.h>
0016 #include <linux/iio/events.h>
0017 #include <linux/iio/consumer.h> /* To get our ADC channel */
0018 #include <linux/iio/types.h> /* To deal with our ADC channel */
0019 #include <linux/init.h>
0020 #include <linux/leds.h>
0021 #include <linux/platform_device.h>
0022 #include <linux/property.h>
0023 #include <linux/regulator/consumer.h>
0024 #include <linux/gpio/consumer.h>
0025 #include <linux/interrupt.h>
0026 #include <linux/math64.h>
0027 #include <linux/pm.h>
0028
0029 #define CM3605_PROX_CHANNEL 0
0030 #define CM3605_ALS_CHANNEL 1
0031 #define CM3605_AOUT_TYP_MAX_MV 1550
0032
0033 #define CM3605_AOUT_MAX_MV 1650
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 struct cm3605 {
0046 struct device *dev;
0047 struct regulator *vdd;
0048 struct gpio_desc *aset;
0049 struct iio_channel *aout;
0050 s32 als_max;
0051 enum iio_event_direction dir;
0052 struct led_trigger *led;
0053 };
0054
0055 static irqreturn_t cm3605_prox_irq(int irq, void *d)
0056 {
0057 struct iio_dev *indio_dev = d;
0058 struct cm3605 *cm3605 = iio_priv(indio_dev);
0059 u64 ev;
0060
0061 ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, CM3605_PROX_CHANNEL,
0062 IIO_EV_TYPE_THRESH, cm3605->dir);
0063 iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev));
0064
0065
0066 if (cm3605->dir == IIO_EV_DIR_RISING)
0067 cm3605->dir = IIO_EV_DIR_FALLING;
0068 else
0069 cm3605->dir = IIO_EV_DIR_RISING;
0070
0071 return IRQ_HANDLED;
0072 }
0073
0074 static int cm3605_get_lux(struct cm3605 *cm3605)
0075 {
0076 int ret, res;
0077 s64 lux;
0078
0079 ret = iio_read_channel_processed(cm3605->aout, &res);
0080 if (ret < 0)
0081 return ret;
0082
0083 dev_dbg(cm3605->dev, "read %d mV from ADC\n", res);
0084
0085
0086
0087
0088
0089
0090
0091 if (res < 30)
0092 return 0;
0093 if (res > CM3605_AOUT_MAX_MV)
0094 dev_err(cm3605->dev, "device out of range\n");
0095
0096
0097 lux = res - 30;
0098
0099
0100 lux *= cm3605->als_max;
0101 lux = div64_s64(lux, CM3605_AOUT_TYP_MAX_MV);
0102
0103 return lux;
0104 }
0105
0106 static int cm3605_read_raw(struct iio_dev *indio_dev,
0107 struct iio_chan_spec const *chan,
0108 int *val, int *val2, long mask)
0109 {
0110 struct cm3605 *cm3605 = iio_priv(indio_dev);
0111 int ret;
0112
0113 switch (mask) {
0114 case IIO_CHAN_INFO_RAW:
0115 switch (chan->type) {
0116 case IIO_LIGHT:
0117 ret = cm3605_get_lux(cm3605);
0118 if (ret < 0)
0119 return ret;
0120 *val = ret;
0121 return IIO_VAL_INT;
0122 default:
0123 return -EINVAL;
0124 }
0125 default:
0126 return -EINVAL;
0127 }
0128 }
0129
0130 static const struct iio_info cm3605_info = {
0131 .read_raw = cm3605_read_raw,
0132 };
0133
0134 static const struct iio_event_spec cm3605_events[] = {
0135 {
0136 .type = IIO_EV_TYPE_THRESH,
0137 .dir = IIO_EV_DIR_EITHER,
0138 .mask_separate = BIT(IIO_EV_INFO_ENABLE),
0139 },
0140 };
0141
0142 static const struct iio_chan_spec cm3605_channels[] = {
0143 {
0144 .type = IIO_PROXIMITY,
0145 .event_spec = cm3605_events,
0146 .num_event_specs = ARRAY_SIZE(cm3605_events),
0147 },
0148 {
0149 .type = IIO_LIGHT,
0150 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0151 .channel = CM3605_ALS_CHANNEL,
0152 },
0153 };
0154
0155 static int cm3605_probe(struct platform_device *pdev)
0156 {
0157 struct cm3605 *cm3605;
0158 struct iio_dev *indio_dev;
0159 struct device *dev = &pdev->dev;
0160 enum iio_chan_type ch_type;
0161 u32 rset;
0162 int irq;
0163 int ret;
0164
0165 indio_dev = devm_iio_device_alloc(dev, sizeof(*cm3605));
0166 if (!indio_dev)
0167 return -ENOMEM;
0168 platform_set_drvdata(pdev, indio_dev);
0169
0170 cm3605 = iio_priv(indio_dev);
0171 cm3605->dev = dev;
0172 cm3605->dir = IIO_EV_DIR_FALLING;
0173
0174 ret = device_property_read_u32(dev, "capella,aset-resistance-ohms", &rset);
0175 if (ret) {
0176 dev_info(dev, "no RSET specified, assuming 100K\n");
0177 rset = 100000;
0178 }
0179 switch (rset) {
0180 case 50000:
0181 cm3605->als_max = 650;
0182 break;
0183 case 100000:
0184 cm3605->als_max = 300;
0185 break;
0186 case 300000:
0187 cm3605->als_max = 100;
0188 break;
0189 case 600000:
0190 cm3605->als_max = 50;
0191 break;
0192 default:
0193 dev_info(dev, "non-standard resistance\n");
0194 return -EINVAL;
0195 }
0196
0197 cm3605->aout = devm_iio_channel_get(dev, "aout");
0198 if (IS_ERR(cm3605->aout)) {
0199 ret = PTR_ERR(cm3605->aout);
0200 ret = (ret == -ENODEV) ? -EPROBE_DEFER : ret;
0201 return dev_err_probe(dev, ret, "failed to get AOUT ADC channel\n");
0202 }
0203 ret = iio_get_channel_type(cm3605->aout, &ch_type);
0204 if (ret < 0)
0205 return ret;
0206 if (ch_type != IIO_VOLTAGE) {
0207 dev_err(dev, "wrong type of IIO channel specified for AOUT\n");
0208 return -EINVAL;
0209 }
0210
0211 cm3605->vdd = devm_regulator_get(dev, "vdd");
0212 if (IS_ERR(cm3605->vdd))
0213 return dev_err_probe(dev, PTR_ERR(cm3605->vdd),
0214 "failed to get VDD regulator\n");
0215
0216 ret = regulator_enable(cm3605->vdd);
0217 if (ret) {
0218 dev_err(dev, "failed to enable VDD regulator\n");
0219 return ret;
0220 }
0221
0222 cm3605->aset = devm_gpiod_get(dev, "aset", GPIOD_OUT_HIGH);
0223 if (IS_ERR(cm3605->aset)) {
0224 ret = dev_err_probe(dev, PTR_ERR(cm3605->aset), "no ASET GPIO\n");
0225 goto out_disable_vdd;
0226 }
0227
0228 irq = platform_get_irq(pdev, 0);
0229 if (irq < 0) {
0230 ret = dev_err_probe(dev, irq, "failed to get irq\n");
0231 goto out_disable_aset;
0232 }
0233
0234 ret = devm_request_threaded_irq(dev, irq, cm3605_prox_irq,
0235 NULL, 0, "cm3605", indio_dev);
0236 if (ret) {
0237 dev_err(dev, "unable to request IRQ\n");
0238 goto out_disable_aset;
0239 }
0240
0241
0242 led_trigger_register_simple("cm3605", &cm3605->led);
0243 led_trigger_event(cm3605->led, LED_FULL);
0244
0245 indio_dev->info = &cm3605_info;
0246 indio_dev->name = "cm3605";
0247 indio_dev->channels = cm3605_channels;
0248 indio_dev->num_channels = ARRAY_SIZE(cm3605_channels);
0249 indio_dev->modes = INDIO_DIRECT_MODE;
0250
0251 ret = iio_device_register(indio_dev);
0252 if (ret)
0253 goto out_remove_trigger;
0254 dev_info(dev, "Capella Microsystems CM3605 enabled range 0..%d LUX\n",
0255 cm3605->als_max);
0256
0257 return 0;
0258
0259 out_remove_trigger:
0260 led_trigger_event(cm3605->led, LED_OFF);
0261 led_trigger_unregister_simple(cm3605->led);
0262 out_disable_aset:
0263 gpiod_set_value_cansleep(cm3605->aset, 0);
0264 out_disable_vdd:
0265 regulator_disable(cm3605->vdd);
0266 return ret;
0267 }
0268
0269 static int cm3605_remove(struct platform_device *pdev)
0270 {
0271 struct iio_dev *indio_dev = platform_get_drvdata(pdev);
0272 struct cm3605 *cm3605 = iio_priv(indio_dev);
0273
0274 led_trigger_event(cm3605->led, LED_OFF);
0275 led_trigger_unregister_simple(cm3605->led);
0276 gpiod_set_value_cansleep(cm3605->aset, 0);
0277 iio_device_unregister(indio_dev);
0278 regulator_disable(cm3605->vdd);
0279
0280 return 0;
0281 }
0282
0283 static int cm3605_pm_suspend(struct device *dev)
0284 {
0285 struct iio_dev *indio_dev = dev_get_drvdata(dev);
0286 struct cm3605 *cm3605 = iio_priv(indio_dev);
0287
0288 led_trigger_event(cm3605->led, LED_OFF);
0289 regulator_disable(cm3605->vdd);
0290
0291 return 0;
0292 }
0293
0294 static int cm3605_pm_resume(struct device *dev)
0295 {
0296 struct iio_dev *indio_dev = dev_get_drvdata(dev);
0297 struct cm3605 *cm3605 = iio_priv(indio_dev);
0298 int ret;
0299
0300 ret = regulator_enable(cm3605->vdd);
0301 if (ret)
0302 dev_err(dev, "failed to enable regulator in resume path\n");
0303 led_trigger_event(cm3605->led, LED_FULL);
0304
0305 return 0;
0306 }
0307 static DEFINE_SIMPLE_DEV_PM_OPS(cm3605_dev_pm_ops, cm3605_pm_suspend,
0308 cm3605_pm_resume);
0309
0310 static const struct of_device_id cm3605_of_match[] = {
0311 {.compatible = "capella,cm3605"},
0312 { },
0313 };
0314 MODULE_DEVICE_TABLE(of, cm3605_of_match);
0315
0316 static struct platform_driver cm3605_driver = {
0317 .driver = {
0318 .name = "cm3605",
0319 .of_match_table = cm3605_of_match,
0320 .pm = pm_sleep_ptr(&cm3605_dev_pm_ops),
0321 },
0322 .probe = cm3605_probe,
0323 .remove = cm3605_remove,
0324 };
0325 module_platform_driver(cm3605_driver);
0326
0327 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
0328 MODULE_DESCRIPTION("CM3605 ambient light and proximity sensor driver");
0329 MODULE_LICENSE("GPL");