linux/drivers/iio/magnetometer/ak09911.c
<<
>>
Prefs
   1/*
   2 * AK09911 3-axis compass driver
   3 * Copyright (c) 2014, Intel Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/module.h>
  17#include <linux/init.h>
  18#include <linux/types.h>
  19#include <linux/slab.h>
  20#include <linux/delay.h>
  21#include <linux/i2c.h>
  22#include <linux/acpi.h>
  23#include <linux/iio/iio.h>
  24
  25#define AK09911_REG_WIA1                0x00
  26#define AK09911_REG_WIA2                0x01
  27#define AK09911_WIA1_VALUE              0x48
  28#define AK09911_WIA2_VALUE              0x05
  29
  30#define AK09911_REG_ST1                 0x10
  31#define AK09911_REG_HXL                 0x11
  32#define AK09911_REG_HXH                 0x12
  33#define AK09911_REG_HYL                 0x13
  34#define AK09911_REG_HYH                 0x14
  35#define AK09911_REG_HZL                 0x15
  36#define AK09911_REG_HZH                 0x16
  37
  38#define AK09911_REG_ASAX                0x60
  39#define AK09911_REG_ASAY                0x61
  40#define AK09911_REG_ASAZ                0x62
  41
  42#define AK09911_REG_CNTL1               0x30
  43#define AK09911_REG_CNTL2               0x31
  44#define AK09911_REG_CNTL3               0x32
  45
  46#define AK09911_MODE_SNG_MEASURE        0x01
  47#define AK09911_MODE_SELF_TEST          0x10
  48#define AK09911_MODE_FUSE_ACCESS        0x1F
  49#define AK09911_MODE_POWERDOWN          0x00
  50#define AK09911_RESET_DATA              0x01
  51
  52#define AK09911_REG_CNTL1               0x30
  53#define AK09911_REG_CNTL2               0x31
  54#define AK09911_REG_CNTL3               0x32
  55
  56#define AK09911_RAW_TO_GAUSS(asa)       ((((asa) + 128) * 6000) / 256)
  57
  58#define AK09911_MAX_CONVERSION_TIMEOUT_MS       500
  59#define AK09911_CONVERSION_DONE_POLL_TIME_MS    10
  60
  61struct ak09911_data {
  62        struct i2c_client       *client;
  63        struct mutex            lock;
  64        u8                      asa[3];
  65        long                    raw_to_gauss[3];
  66};
  67
  68static const int ak09911_index_to_reg[] = {
  69        AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
  70};
  71
  72static int ak09911_set_mode(struct i2c_client *client, u8 mode)
  73{
  74        int ret;
  75
  76        switch (mode) {
  77        case AK09911_MODE_SNG_MEASURE:
  78        case AK09911_MODE_SELF_TEST:
  79        case AK09911_MODE_FUSE_ACCESS:
  80        case AK09911_MODE_POWERDOWN:
  81                ret = i2c_smbus_write_byte_data(client,
  82                                                AK09911_REG_CNTL2, mode);
  83                if (ret < 0) {
  84                        dev_err(&client->dev, "set_mode error\n");
  85                        return ret;
  86                }
  87                /* After mode change wait atleast 100us */
  88                usleep_range(100, 500);
  89                break;
  90        default:
  91                dev_err(&client->dev,
  92                        "%s: Unknown mode(%d).", __func__, mode);
  93                return -EINVAL;
  94        }
  95
  96        return ret;
  97}
  98
  99/* Get Sensitivity Adjustment value */
 100static int ak09911_get_asa(struct i2c_client *client)
 101{
 102        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 103        struct ak09911_data *data = iio_priv(indio_dev);
 104        int ret;
 105
 106        ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
 107        if (ret < 0)
 108                return ret;
 109
 110        /* Get asa data and store in the device data. */
 111        ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
 112                                            3, data->asa);
 113        if (ret < 0) {
 114                dev_err(&client->dev, "Not able to read asa data\n");
 115                return ret;
 116        }
 117
 118        ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
 119        if (ret < 0)
 120                return ret;
 121
 122        data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
 123        data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
 124        data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
 125
 126        return 0;
 127}
 128
 129static int ak09911_verify_chip_id(struct i2c_client *client)
 130{
 131        u8 wia_val[2];
 132        int ret;
 133
 134        ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
 135                                            2, wia_val);
 136        if (ret < 0) {
 137                dev_err(&client->dev, "Error reading WIA\n");
 138                return ret;
 139        }
 140
 141        dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
 142
 143        if (wia_val[0] != AK09911_WIA1_VALUE ||
 144                wia_val[1] != AK09911_WIA2_VALUE) {
 145                dev_err(&client->dev, "Device ak09911 not found\n");
 146                return -ENODEV;
 147        }
 148
 149        return 0;
 150}
 151
 152static int wait_conversion_complete_polled(struct ak09911_data *data)
 153{
 154        struct i2c_client *client = data->client;
 155        u8 read_status;
 156        u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
 157        int ret;
 158
 159        /* Wait for the conversion to complete. */
 160        while (timeout_ms) {
 161                msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
 162                ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
 163                if (ret < 0) {
 164                        dev_err(&client->dev, "Error in reading ST1\n");
 165                        return ret;
 166                }
 167                read_status = ret & 0x01;
 168                if (read_status)
 169                        break;
 170                timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
 171        }
 172        if (!timeout_ms) {
 173                dev_err(&client->dev, "Conversion timeout happened\n");
 174                return -EIO;
 175        }
 176
 177        return read_status;
 178}
 179
 180static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
 181{
 182        struct ak09911_data *data = iio_priv(indio_dev);
 183        struct i2c_client *client = data->client;
 184        int ret;
 185
 186        mutex_lock(&data->lock);
 187
 188        ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
 189        if (ret < 0)
 190                goto fn_exit;
 191
 192        ret = wait_conversion_complete_polled(data);
 193        if (ret < 0)
 194                goto fn_exit;
 195
 196        /* Read data */
 197        ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
 198        if (ret < 0) {
 199                dev_err(&client->dev, "Read axis data fails\n");
 200                goto fn_exit;
 201        }
 202
 203        mutex_unlock(&data->lock);
 204
 205        /* Clamp to valid range. */
 206        *val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
 207
 208        return IIO_VAL_INT;
 209
 210fn_exit:
 211        mutex_unlock(&data->lock);
 212
 213        return ret;
 214}
 215
 216static int ak09911_read_raw(struct iio_dev *indio_dev,
 217                            struct iio_chan_spec const *chan,
 218                            int *val, int *val2,
 219                            long mask)
 220{
 221        struct ak09911_data *data = iio_priv(indio_dev);
 222
 223        switch (mask) {
 224        case IIO_CHAN_INFO_RAW:
 225                return ak09911_read_axis(indio_dev, chan->address, val);
 226        case IIO_CHAN_INFO_SCALE:
 227                *val = 0;
 228                *val2 = data->raw_to_gauss[chan->address];
 229                return IIO_VAL_INT_PLUS_MICRO;
 230        }
 231
 232        return -EINVAL;
 233}
 234
 235#define AK09911_CHANNEL(axis, index)                                    \
 236        {                                                               \
 237                .type = IIO_MAGN,                                       \
 238                .modified = 1,                                          \
 239                .channel2 = IIO_MOD_##axis,                             \
 240                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |          \
 241                             BIT(IIO_CHAN_INFO_SCALE),                  \
 242                .address = index,                                       \
 243        }
 244
 245static const struct iio_chan_spec ak09911_channels[] = {
 246        AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
 247};
 248
 249static const struct iio_info ak09911_info = {
 250        .read_raw = &ak09911_read_raw,
 251        .driver_module = THIS_MODULE,
 252};
 253
 254static const struct acpi_device_id ak_acpi_match[] = {
 255        {"AK009911", 0},
 256        { },
 257};
 258MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
 259
 260static int ak09911_probe(struct i2c_client *client,
 261                         const struct i2c_device_id *id)
 262{
 263        struct iio_dev *indio_dev;
 264        struct ak09911_data *data;
 265        const char *name;
 266        int ret;
 267
 268        ret = ak09911_verify_chip_id(client);
 269        if (ret) {
 270                dev_err(&client->dev, "AK00911 not detected\n");
 271                return -ENODEV;
 272        }
 273
 274        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 275        if (indio_dev == NULL)
 276                return -ENOMEM;
 277
 278        data = iio_priv(indio_dev);
 279        i2c_set_clientdata(client, indio_dev);
 280
 281        data->client = client;
 282        mutex_init(&data->lock);
 283
 284        ret = ak09911_get_asa(client);
 285        if (ret)
 286                return ret;
 287
 288        if (id)
 289                name = id->name;
 290        else if (ACPI_HANDLE(&client->dev))
 291                name = dev_name(&client->dev);
 292        else
 293                return -ENODEV;
 294
 295        dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
 296
 297        indio_dev->dev.parent = &client->dev;
 298        indio_dev->channels = ak09911_channels;
 299        indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
 300        indio_dev->info = &ak09911_info;
 301        indio_dev->modes = INDIO_DIRECT_MODE;
 302        indio_dev->name = name;
 303
 304        return devm_iio_device_register(&client->dev, indio_dev);
 305}
 306
 307static const struct i2c_device_id ak09911_id[] = {
 308        {"ak09911", 0},
 309        {}
 310};
 311
 312MODULE_DEVICE_TABLE(i2c, ak09911_id);
 313
 314static struct i2c_driver ak09911_driver = {
 315        .driver = {
 316                .name   = "ak09911",
 317                .acpi_match_table = ACPI_PTR(ak_acpi_match),
 318        },
 319        .probe          = ak09911_probe,
 320        .id_table       = ak09911_id,
 321};
 322module_i2c_driver(ak09911_driver);
 323
 324MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
 325MODULE_LICENSE("GPL v2");
 326MODULE_DESCRIPTION("AK09911 Compass driver");
 327