staging:iio:hmc5843: Use SCALE instead of magn_range
authorPeter Meerwald <pmeerw@pmeerw.net>
Wed, 16 Oct 2013 22:19:00 +0000 (23:19 +0100)
committerJonathan Cameron <jic23@kernel.org>
Thu, 17 Oct 2013 22:45:09 +0000 (23:45 +0100)
v3:
* rename _check_scale() to _get_scale_index()
v2:
* use SCALE instead of CALIBSCALE to control the range/gain
  of measurements

Signed-off-by: Peter Meerwald <pmeerw@pmeerw.net>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
drivers/staging/iio/magnetometer/hmc5843.c

index b29622c6f157d52b088d871b5b65d1a708889e1e..c56db4109119be1343a006fb558afc427431cf12 100644 (file)
@@ -49,7 +49,7 @@ enum hmc5843_ids {
  */
 #define HMC5843_RANGE_GAIN_OFFSET              0x05
 #define HMC5843_RANGE_GAIN_DEFAULT             0x01
-#define HMC5843_RANGE_GAIN_MAX                 0x07
+#define HMC5843_RANGE_GAINS                    8
 
 /* Device status */
 #define HMC5843_DATA_READY                     0x01
@@ -79,64 +79,18 @@ enum hmc5843_ids {
 #define HMC5843_MEAS_CONF_MASK                 0x03
 
 /* Scaling factors: 10000000/Gain */
-static const int hmc5843_regval_to_nanoscale[] = {
+static const int hmc5843_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
        6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714
 };
 
-static const int hmc5883_regval_to_nanoscale[] = {
+static const int hmc5883_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
        7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662
 };
 
-static const int hmc5883l_regval_to_nanoscale[] = {
+static const int hmc5883l_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
        7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478
 };
 
-/*
- * From the HMC5843 datasheet:
- * Value       | Sensor input field range (Ga) | Gain (counts/milli-Gauss)
- * 0           | (+-)0.7                       | 1620
- * 1           | (+-)1.0                       | 1300
- * 2           | (+-)1.5                       | 970
- * 3           | (+-)2.0                       | 780
- * 4           | (+-)3.2                       | 530
- * 5           | (+-)3.8                       | 460
- * 6           | (+-)4.5                       | 390
- * 7           | (+-)6.5                       | 280
- *
- * From the HMC5883 datasheet:
- * Value       | Recommended sensor field range (Ga)   | Gain (counts/Gauss)
- * 0           | (+-)0.9                               | 1280
- * 1           | (+-)1.2                               | 1024
- * 2           | (+-)1.9                               | 768
- * 3           | (+-)2.5                               | 614
- * 4           | (+-)4.0                               | 415
- * 5           | (+-)4.6                               | 361
- * 6           | (+-)5.5                               | 307
- * 7           | (+-)7.9                               | 219
- *
- * From the HMC5883L datasheet:
- * Value       | Recommended sensor field range (Ga)   | Gain (LSB/Gauss)
- * 0           | (+-)0.88                              | 1370
- * 1           | (+-)1.3                               | 1090
- * 2           | (+-)1.9                               | 820
- * 3           | (+-)2.5                               | 660
- * 4           | (+-)4.0                               | 440
- * 5           | (+-)4.7                               | 390
- * 6           | (+-)5.6                               | 330
- * 7           | (+-)8.1                               | 230
- */
-static const int hmc5843_regval_to_input_field_mga[] = {
-       700, 1000, 1500, 2000, 3200, 3800, 4500, 6500
-};
-
-static const int hmc5883_regval_to_input_field_mga[] = {
-       900, 1200, 1900, 2500, 4000, 4600, 5500, 7900
-};
-
-static const int hmc5883l_regval_to_input_field_mga[] = {
-       880, 1300, 1900, 2500, 4000, 4700, 5600, 8100
-};
-
 /*
  * From the datasheet:
  * Value       | HMC5843               | HMC5883/HMC5883L
@@ -163,7 +117,6 @@ static const int hmc5883_regval_to_samp_freq[7][2] = {
 struct hmc5843_chip_info {
        const struct iio_chan_spec *channels;
        const int (*regval_to_samp_freq)[2];
-       const int *regval_to_input_field_mga;
        const int *regval_to_nanoscale;
 };
 
@@ -412,58 +365,41 @@ static int hmc5843_check_samp_freq(struct hmc5843_data *data,
                val, val2);
 }
 
-static ssize_t hmc5843_show_range_gain(struct device *dev,
-                               struct device_attribute *attr,
-                               char *buf)
+static ssize_t hmc5843_show_scale_avail(struct device *dev,
+                               struct device_attribute *attr, char *buf)
 {
-       u8 range;
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct hmc5843_data *data = iio_priv(indio_dev);
+       struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
+
+       size_t len = 0;
+       int i;
 
-       range = data->range;
-       return sprintf(buf, "%d\n", data->variant->regval_to_input_field_mga[range]);
+       for (i = 0; i < HMC5843_RANGE_GAINS; i++)
+               len += scnprintf(buf + len, PAGE_SIZE - len,
+                       "0.%09d ", data->variant->regval_to_nanoscale[i]);
+
+       /* replace trailing space by newline */
+       buf[len - 1] = '\n';
+
+       return len;
 }
 
-static ssize_t hmc5843_set_range_gain(struct device *dev,
-                       struct device_attribute *attr,
-                       const char *buf,
-                       size_t count)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-       struct hmc5843_data *data = iio_priv(indio_dev);
-       unsigned long range = 0;
-       int error;
+static IIO_DEVICE_ATTR(scale_available, S_IRUGO,
+       hmc5843_show_scale_avail, NULL, 0);
 
-       mutex_lock(&data->lock);
-       error = kstrtoul(buf, 10, &range);
-       if (error) {
-               count = error;
-               goto exit;
-       }
-       dev_dbg(dev, "set range to %lu\n", range);
+static int hmc5843_get_scale_index(struct hmc5843_data *data, int val, int val2)
+{
+       int i;
 
-       if (range > HMC5843_RANGE_GAIN_MAX) {
-               count = -EINVAL;
-               goto exit;
-       }
+       if (val != 0)
+               return -EINVAL;
 
-       data->range = range;
-       range = range << HMC5843_RANGE_GAIN_OFFSET;
-       if (i2c_smbus_write_byte_data(data->client, this_attr->address, range))
-               count = -EINVAL;
+       for (i = 0; i < HMC5843_RANGE_GAINS; i++)
+               if (val2 == data->variant->regval_to_nanoscale[i])
+                       return i;
 
-exit:
-       mutex_unlock(&data->lock);
-       return count;
+       return -EINVAL;
 }
 
-static IIO_DEVICE_ATTR(in_magn_range,
-                       S_IWUSR | S_IRUGO,
-                       hmc5843_show_range_gain,
-                       hmc5843_set_range_gain,
-                       HMC5843_CONFIG_REG_B);
-
 static int hmc5843_read_raw(struct iio_dev *indio_dev,
                            struct iio_chan_spec const *chan,
                            int *val, int *val2, long mask)
@@ -490,7 +426,7 @@ static int hmc5843_write_raw(struct iio_dev *indio_dev,
                             int val, int val2, long mask)
 {
        struct hmc5843_data *data = iio_priv(indio_dev);
-       int ret, rate;
+       int ret, rate, range;
 
        switch (mask) {
        case IIO_CHAN_INFO_SAMP_FREQ:
@@ -505,6 +441,33 @@ static int hmc5843_write_raw(struct iio_dev *indio_dev,
                mutex_unlock(&data->lock);
 
                return ret;
+       case IIO_CHAN_INFO_SCALE:
+               range = hmc5843_get_scale_index(data, val, val2);
+               if (range < 0)
+                       return -EINVAL;
+
+               range <<= HMC5843_RANGE_GAIN_OFFSET;
+               mutex_lock(&data->lock);
+               ret = i2c_smbus_write_byte_data(data->client,
+                       HMC5843_CONFIG_REG_B, range);
+               if (ret >= 0)
+                       data->range = range;
+               mutex_unlock(&data->lock);
+
+               return ret;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int hmc5843_write_raw_get_fmt(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan, long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               return IIO_VAL_INT_PLUS_MICRO;
+       case IIO_CHAN_INFO_SCALE:
+               return IIO_VAL_INT_PLUS_NANO;
        default:
                return -EINVAL;
        }
@@ -536,7 +499,7 @@ static const struct iio_chan_spec hmc5883_channels[] = {
 static struct attribute *hmc5843_attributes[] = {
        &iio_dev_attr_meas_conf.dev_attr.attr,
        &iio_dev_attr_operating_mode.dev_attr.attr,
-       &iio_dev_attr_in_magn_range.dev_attr.attr,
+       &iio_dev_attr_scale_available.dev_attr.attr,
        &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
        NULL
 };
@@ -549,22 +512,16 @@ static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
        [HMC5843_ID] = {
                .channels = hmc5843_channels,
                .regval_to_samp_freq = hmc5843_regval_to_samp_freq,
-               .regval_to_input_field_mga =
-                       hmc5843_regval_to_input_field_mga,
                .regval_to_nanoscale = hmc5843_regval_to_nanoscale,
        },
        [HMC5883_ID] = {
                .channels = hmc5883_channels,
                .regval_to_samp_freq = hmc5883_regval_to_samp_freq,
-               .regval_to_input_field_mga =
-                       hmc5883_regval_to_input_field_mga,
                .regval_to_nanoscale = hmc5883_regval_to_nanoscale,
        },
        [HMC5883L_ID] = {
                .channels = hmc5883_channels,
                .regval_to_samp_freq = hmc5883_regval_to_samp_freq,
-               .regval_to_input_field_mga =
-                       hmc5883l_regval_to_input_field_mga,
                .regval_to_nanoscale = hmc5883l_regval_to_nanoscale,
        },
 };
@@ -582,6 +539,7 @@ static const struct iio_info hmc5843_info = {
        .attrs = &hmc5843_group,
        .read_raw = &hmc5843_read_raw,
        .write_raw = &hmc5843_write_raw,
+       .write_raw_get_fmt = &hmc5843_write_raw_get_fmt,
        .driver_module = THIS_MODULE,
 };