1*64a70c65SLudovic Tancerel /* 2*64a70c65SLudovic Tancerel * ms5637.c - Support for Measurement-Specialties ms5637 3*64a70c65SLudovic Tancerel * pressure & temperature sensor 4*64a70c65SLudovic Tancerel * 5*64a70c65SLudovic Tancerel * Copyright (c) 2015 Measurement-Specialties 6*64a70c65SLudovic Tancerel * 7*64a70c65SLudovic Tancerel * Licensed under the GPL-2. 8*64a70c65SLudovic Tancerel * 9*64a70c65SLudovic Tancerel * (7-bit I2C slave address 0x76) 10*64a70c65SLudovic Tancerel * 11*64a70c65SLudovic Tancerel * Datasheet: 12*64a70c65SLudovic Tancerel * http://www.meas-spec.com/downloads/MS5637-02BA03.pdf 13*64a70c65SLudovic Tancerel */ 14*64a70c65SLudovic Tancerel #include <linux/init.h> 15*64a70c65SLudovic Tancerel #include <linux/device.h> 16*64a70c65SLudovic Tancerel #include <linux/kernel.h> 17*64a70c65SLudovic Tancerel #include <linux/stat.h> 18*64a70c65SLudovic Tancerel #include <linux/module.h> 19*64a70c65SLudovic Tancerel #include <linux/i2c.h> 20*64a70c65SLudovic Tancerel #include <linux/iio/iio.h> 21*64a70c65SLudovic Tancerel #include <linux/iio/sysfs.h> 22*64a70c65SLudovic Tancerel #include <linux/mutex.h> 23*64a70c65SLudovic Tancerel 24*64a70c65SLudovic Tancerel #include "../common/ms_sensors/ms_sensors_i2c.h" 25*64a70c65SLudovic Tancerel 26*64a70c65SLudovic Tancerel static const int ms5637_samp_freq[6] = { 960, 480, 240, 120, 60, 30 }; 27*64a70c65SLudovic Tancerel /* String copy of the above const for readability purpose */ 28*64a70c65SLudovic Tancerel static const char ms5637_show_samp_freq[] = "960 480 240 120 60 30"; 29*64a70c65SLudovic Tancerel 30*64a70c65SLudovic Tancerel static int ms5637_read_raw(struct iio_dev *indio_dev, 31*64a70c65SLudovic Tancerel struct iio_chan_spec const *channel, int *val, 32*64a70c65SLudovic Tancerel int *val2, long mask) 33*64a70c65SLudovic Tancerel { 34*64a70c65SLudovic Tancerel int ret; 35*64a70c65SLudovic Tancerel int temperature; 36*64a70c65SLudovic Tancerel unsigned int pressure; 37*64a70c65SLudovic Tancerel struct ms_tp_dev *dev_data = iio_priv(indio_dev); 38*64a70c65SLudovic Tancerel 39*64a70c65SLudovic Tancerel switch (mask) { 40*64a70c65SLudovic Tancerel case IIO_CHAN_INFO_PROCESSED: 41*64a70c65SLudovic Tancerel ret = ms_sensors_read_temp_and_pressure(dev_data, 42*64a70c65SLudovic Tancerel &temperature, 43*64a70c65SLudovic Tancerel &pressure); 44*64a70c65SLudovic Tancerel if (ret) 45*64a70c65SLudovic Tancerel return ret; 46*64a70c65SLudovic Tancerel 47*64a70c65SLudovic Tancerel switch (channel->type) { 48*64a70c65SLudovic Tancerel case IIO_TEMP: /* in milli °C */ 49*64a70c65SLudovic Tancerel *val = temperature; 50*64a70c65SLudovic Tancerel 51*64a70c65SLudovic Tancerel return IIO_VAL_INT; 52*64a70c65SLudovic Tancerel case IIO_PRESSURE: /* in kPa */ 53*64a70c65SLudovic Tancerel *val = pressure / 1000; 54*64a70c65SLudovic Tancerel *val2 = (pressure % 1000) * 1000; 55*64a70c65SLudovic Tancerel 56*64a70c65SLudovic Tancerel return IIO_VAL_INT_PLUS_MICRO; 57*64a70c65SLudovic Tancerel default: 58*64a70c65SLudovic Tancerel return -EINVAL; 59*64a70c65SLudovic Tancerel } 60*64a70c65SLudovic Tancerel case IIO_CHAN_INFO_SAMP_FREQ: 61*64a70c65SLudovic Tancerel *val = ms5637_samp_freq[dev_data->res_index]; 62*64a70c65SLudovic Tancerel 63*64a70c65SLudovic Tancerel return IIO_VAL_INT; 64*64a70c65SLudovic Tancerel default: 65*64a70c65SLudovic Tancerel return -EINVAL; 66*64a70c65SLudovic Tancerel } 67*64a70c65SLudovic Tancerel } 68*64a70c65SLudovic Tancerel 69*64a70c65SLudovic Tancerel static int ms5637_write_raw(struct iio_dev *indio_dev, 70*64a70c65SLudovic Tancerel struct iio_chan_spec const *chan, 71*64a70c65SLudovic Tancerel int val, int val2, long mask) 72*64a70c65SLudovic Tancerel { 73*64a70c65SLudovic Tancerel struct ms_tp_dev *dev_data = iio_priv(indio_dev); 74*64a70c65SLudovic Tancerel int i; 75*64a70c65SLudovic Tancerel 76*64a70c65SLudovic Tancerel switch (mask) { 77*64a70c65SLudovic Tancerel case IIO_CHAN_INFO_SAMP_FREQ: 78*64a70c65SLudovic Tancerel i = ARRAY_SIZE(ms5637_samp_freq); 79*64a70c65SLudovic Tancerel while (i-- > 0) 80*64a70c65SLudovic Tancerel if (val == ms5637_samp_freq[i]) 81*64a70c65SLudovic Tancerel break; 82*64a70c65SLudovic Tancerel if (i < 0) 83*64a70c65SLudovic Tancerel return -EINVAL; 84*64a70c65SLudovic Tancerel dev_data->res_index = i; 85*64a70c65SLudovic Tancerel 86*64a70c65SLudovic Tancerel return 0; 87*64a70c65SLudovic Tancerel default: 88*64a70c65SLudovic Tancerel return -EINVAL; 89*64a70c65SLudovic Tancerel } 90*64a70c65SLudovic Tancerel } 91*64a70c65SLudovic Tancerel 92*64a70c65SLudovic Tancerel static const struct iio_chan_spec ms5637_channels[] = { 93*64a70c65SLudovic Tancerel { 94*64a70c65SLudovic Tancerel .type = IIO_TEMP, 95*64a70c65SLudovic Tancerel .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 96*64a70c65SLudovic Tancerel .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), 97*64a70c65SLudovic Tancerel }, 98*64a70c65SLudovic Tancerel { 99*64a70c65SLudovic Tancerel .type = IIO_PRESSURE, 100*64a70c65SLudovic Tancerel .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 101*64a70c65SLudovic Tancerel .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), 102*64a70c65SLudovic Tancerel } 103*64a70c65SLudovic Tancerel }; 104*64a70c65SLudovic Tancerel 105*64a70c65SLudovic Tancerel static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(ms5637_show_samp_freq); 106*64a70c65SLudovic Tancerel 107*64a70c65SLudovic Tancerel static struct attribute *ms5637_attributes[] = { 108*64a70c65SLudovic Tancerel &iio_const_attr_sampling_frequency_available.dev_attr.attr, 109*64a70c65SLudovic Tancerel NULL, 110*64a70c65SLudovic Tancerel }; 111*64a70c65SLudovic Tancerel 112*64a70c65SLudovic Tancerel static const struct attribute_group ms5637_attribute_group = { 113*64a70c65SLudovic Tancerel .attrs = ms5637_attributes, 114*64a70c65SLudovic Tancerel }; 115*64a70c65SLudovic Tancerel 116*64a70c65SLudovic Tancerel static const struct iio_info ms5637_info = { 117*64a70c65SLudovic Tancerel .read_raw = ms5637_read_raw, 118*64a70c65SLudovic Tancerel .write_raw = ms5637_write_raw, 119*64a70c65SLudovic Tancerel .attrs = &ms5637_attribute_group, 120*64a70c65SLudovic Tancerel .driver_module = THIS_MODULE, 121*64a70c65SLudovic Tancerel }; 122*64a70c65SLudovic Tancerel 123*64a70c65SLudovic Tancerel static int ms5637_probe(struct i2c_client *client, 124*64a70c65SLudovic Tancerel const struct i2c_device_id *id) 125*64a70c65SLudovic Tancerel { 126*64a70c65SLudovic Tancerel struct ms_tp_dev *dev_data; 127*64a70c65SLudovic Tancerel struct iio_dev *indio_dev; 128*64a70c65SLudovic Tancerel int ret; 129*64a70c65SLudovic Tancerel 130*64a70c65SLudovic Tancerel if (!i2c_check_functionality(client->adapter, 131*64a70c65SLudovic Tancerel I2C_FUNC_SMBUS_READ_WORD_DATA | 132*64a70c65SLudovic Tancerel I2C_FUNC_SMBUS_WRITE_BYTE | 133*64a70c65SLudovic Tancerel I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { 134*64a70c65SLudovic Tancerel dev_err(&client->dev, 135*64a70c65SLudovic Tancerel "Adapter does not support some i2c transaction\n"); 136*64a70c65SLudovic Tancerel return -ENODEV; 137*64a70c65SLudovic Tancerel } 138*64a70c65SLudovic Tancerel 139*64a70c65SLudovic Tancerel indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data)); 140*64a70c65SLudovic Tancerel if (!indio_dev) 141*64a70c65SLudovic Tancerel return -ENOMEM; 142*64a70c65SLudovic Tancerel 143*64a70c65SLudovic Tancerel dev_data = iio_priv(indio_dev); 144*64a70c65SLudovic Tancerel dev_data->client = client; 145*64a70c65SLudovic Tancerel dev_data->res_index = 5; 146*64a70c65SLudovic Tancerel mutex_init(&dev_data->lock); 147*64a70c65SLudovic Tancerel 148*64a70c65SLudovic Tancerel indio_dev->info = &ms5637_info; 149*64a70c65SLudovic Tancerel indio_dev->name = id->name; 150*64a70c65SLudovic Tancerel indio_dev->dev.parent = &client->dev; 151*64a70c65SLudovic Tancerel indio_dev->modes = INDIO_DIRECT_MODE; 152*64a70c65SLudovic Tancerel indio_dev->channels = ms5637_channels; 153*64a70c65SLudovic Tancerel indio_dev->num_channels = ARRAY_SIZE(ms5637_channels); 154*64a70c65SLudovic Tancerel 155*64a70c65SLudovic Tancerel i2c_set_clientdata(client, indio_dev); 156*64a70c65SLudovic Tancerel 157*64a70c65SLudovic Tancerel ret = ms_sensors_reset(client, 0x1E, 3000); 158*64a70c65SLudovic Tancerel if (ret) 159*64a70c65SLudovic Tancerel return ret; 160*64a70c65SLudovic Tancerel 161*64a70c65SLudovic Tancerel ret = ms_sensors_tp_read_prom(dev_data); 162*64a70c65SLudovic Tancerel if (ret) 163*64a70c65SLudovic Tancerel return ret; 164*64a70c65SLudovic Tancerel 165*64a70c65SLudovic Tancerel return devm_iio_device_register(&client->dev, indio_dev); 166*64a70c65SLudovic Tancerel } 167*64a70c65SLudovic Tancerel 168*64a70c65SLudovic Tancerel static const struct i2c_device_id ms5637_id[] = { 169*64a70c65SLudovic Tancerel {"ms5637", 0}, 170*64a70c65SLudovic Tancerel {} 171*64a70c65SLudovic Tancerel }; 172*64a70c65SLudovic Tancerel 173*64a70c65SLudovic Tancerel static struct i2c_driver ms5637_driver = { 174*64a70c65SLudovic Tancerel .probe = ms5637_probe, 175*64a70c65SLudovic Tancerel .id_table = ms5637_id, 176*64a70c65SLudovic Tancerel .driver = { 177*64a70c65SLudovic Tancerel .name = "ms5637" 178*64a70c65SLudovic Tancerel }, 179*64a70c65SLudovic Tancerel }; 180*64a70c65SLudovic Tancerel 181*64a70c65SLudovic Tancerel module_i2c_driver(ms5637_driver); 182*64a70c65SLudovic Tancerel 183*64a70c65SLudovic Tancerel MODULE_DESCRIPTION("Measurement-Specialties ms5637 temperature & pressure driver"); 184*64a70c65SLudovic Tancerel MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>"); 185*64a70c65SLudovic Tancerel MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>"); 186*64a70c65SLudovic Tancerel MODULE_LICENSE("GPL v2"); 187