]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/iio/magnetometer/ak8975.c
Merge tag 'iio-for-3.17b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23...
[karo-tx-linux.git] / drivers / iio / magnetometer / ak8975.c
index 2a524acabec8d5f804186b0ac5d72db7a1c6a4a9..a2357921d7618ce30e2320c6327dab9c7c7f1177 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/bitops.h>
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
+#include <linux/acpi.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #define AK8975_MAX_CONVERSION_TIMEOUT  500
 #define AK8975_CONVERSION_DONE_POLL_TIME 10
 #define AK8975_DATA_READY_TIMEOUT      ((100*HZ)/1000)
-#define RAW_TO_GAUSS(asa) ((((asa) + 128) * 3000) / 256)
+#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
+#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
+
+/* Compatible Asahi Kasei Compass parts */
+enum asahi_compass_chipset {
+       AK8975,
+       AK8963,
+};
 
 /*
  * Per-instance context data for the device.
@@ -101,6 +109,7 @@ struct ak8975_data {
        int                     eoc_irq;
        wait_queue_head_t       data_ready_queue;
        unsigned long           flags;
+       enum asahi_compass_chipset chipset;
 };
 
 static const int ak8975_index_to_reg[] = {
@@ -156,7 +165,7 @@ static int ak8975_setup_irq(struct ak8975_data *data)
        else
                irq = gpio_to_irq(data->eoc_gpio);
 
-       rc = request_irq(irq, ak8975_irq_handler,
+       rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
                         IRQF_TRIGGER_RISING | IRQF_ONESHOT,
                         dev_name(&client->dev), data);
        if (rc < 0) {
@@ -272,9 +281,21 @@ static int ak8975_setup(struct i2c_client *client)
  * Since ASA doesn't change, we cache the resultant scale factor into the
  * device context in ak8975_setup().
  */
-       data->raw_to_gauss[0] = RAW_TO_GAUSS(data->asa[0]);
-       data->raw_to_gauss[1] = RAW_TO_GAUSS(data->asa[1]);
-       data->raw_to_gauss[2] = RAW_TO_GAUSS(data->asa[2]);
+       if (data->chipset == AK8963) {
+               /*
+                * H range is +-8190 and magnetometer range is +-4912.
+                * So HuT using the above explanation for 8975,
+                * 4912/8190 = ~ 6/10.
+                * So the Hadj should use 6/10 instead of 3/10.
+                */
+               data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
+               data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
+               data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
+       } else {
+               data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
+               data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
+               data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
+       }
 
        return 0;
 }
@@ -448,6 +469,27 @@ static const struct iio_info ak8975_info = {
        .driver_module = THIS_MODULE,
 };
 
+static const struct acpi_device_id ak_acpi_match[] = {
+       {"AK8975", AK8975},
+       {"AK8963", AK8963},
+       {"INVN6500", AK8963},
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
+
+static char *ak8975_match_acpi_device(struct device *dev,
+                               enum asahi_compass_chipset *chipset)
+{
+       const struct acpi_device_id *id;
+
+       id = acpi_match_device(dev->driver->acpi_match_table, dev);
+       if (!id)
+               return NULL;
+       *chipset = (int)id->driver_data;
+
+       return (char *)dev_name(dev);
+}
+
 static int ak8975_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -455,6 +497,7 @@ static int ak8975_probe(struct i2c_client *client,
        struct iio_dev *indio_dev;
        int eoc_gpio;
        int err;
+       char *name = NULL;
 
        /* Grab and set up the supplied GPIO. */
        if (client->dev.platform_data)
@@ -470,21 +513,21 @@ static int ak8975_probe(struct i2c_client *client,
        /* We may not have a GPIO based IRQ to scan, that is fine, we will
           poll if so */
        if (gpio_is_valid(eoc_gpio)) {
-               err = gpio_request_one(eoc_gpio, GPIOF_IN, "ak_8975");
+               err = devm_gpio_request_one(&client->dev, eoc_gpio,
+                                                       GPIOF_IN, "ak_8975");
                if (err < 0) {
                        dev_err(&client->dev,
                                "failed to request GPIO %d, error %d\n",
                                                        eoc_gpio, err);
-                       goto exit;
+                       return err;
                }
        }
 
        /* Register with IIO */
-       indio_dev = iio_device_alloc(sizeof(*data));
-       if (indio_dev == NULL) {
-               err = -ENOMEM;
-               goto exit_gpio;
-       }
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+       if (indio_dev == NULL)
+               return -ENOMEM;
+
        data = iio_priv(indio_dev);
        i2c_set_clientdata(client, indio_dev);
 
@@ -492,11 +535,23 @@ static int ak8975_probe(struct i2c_client *client,
        data->eoc_gpio = eoc_gpio;
        data->eoc_irq = 0;
 
+       /* id will be NULL when enumerated via ACPI */
+       if (id) {
+               data->chipset =
+                       (enum asahi_compass_chipset)(id->driver_data);
+               name = (char *) id->name;
+       } else if (ACPI_HANDLE(&client->dev))
+               name = ak8975_match_acpi_device(&client->dev, &data->chipset);
+       else
+               return -ENOSYS;
+
+       dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
+
        /* Perform some basic start-of-day setup of the device. */
        err = ak8975_setup(client);
        if (err < 0) {
                dev_err(&client->dev, "AK8975 initialization fails\n");
-               goto exit_free_iio;
+               return err;
        }
 
        data->client = client;
@@ -506,46 +561,18 @@ static int ak8975_probe(struct i2c_client *client,
        indio_dev->channels = ak8975_channels;
        indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
        indio_dev->info = &ak8975_info;
-       indio_dev->name = id->name;
        indio_dev->modes = INDIO_DIRECT_MODE;
-
-       err = iio_device_register(indio_dev);
+       indio_dev->name = name;
+       err = devm_iio_device_register(&client->dev, indio_dev);
        if (err < 0)
-               goto exit_free_iio;
-
-       return 0;
-
-exit_free_iio:
-       iio_device_free(indio_dev);
-       if (data->eoc_irq)
-               free_irq(data->eoc_irq, data);
-exit_gpio:
-       if (gpio_is_valid(eoc_gpio))
-               gpio_free(eoc_gpio);
-exit:
-       return err;
-}
-
-static int ak8975_remove(struct i2c_client *client)
-{
-       struct iio_dev *indio_dev = i2c_get_clientdata(client);
-       struct ak8975_data *data = iio_priv(indio_dev);
-
-       iio_device_unregister(indio_dev);
-
-       if (data->eoc_irq)
-               free_irq(data->eoc_irq, data);
-
-       if (gpio_is_valid(data->eoc_gpio))
-               gpio_free(data->eoc_gpio);
-
-       iio_device_free(indio_dev);
+               return err;
 
        return 0;
 }
 
 static const struct i2c_device_id ak8975_id[] = {
-       {"ak8975", 0},
+       {"ak8975", AK8975},
+       {"ak8963", AK8963},
        {}
 };
 
@@ -562,9 +589,9 @@ static struct i2c_driver ak8975_driver = {
        .driver = {
                .name   = "ak8975",
                .of_match_table = ak8975_of_match,
+               .acpi_match_table = ACPI_PTR(ak_acpi_match),
        },
        .probe          = ak8975_probe,
-       .remove         = ak8975_remove,
        .id_table       = ak8975_id,
 };
 module_i2c_driver(ak8975_driver);