linux/drivers/iio/accel/bmc150-accel-i2c.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * 3-axis accelerometer driver supporting following I2C Bosch-Sensortec chips:
   4 *  - BMC150
   5 *  - BMI055
   6 *  - BMA255
   7 *  - BMA250E
   8 *  - BMA222
   9 *  - BMA222E
  10 *  - BMA280
  11 *
  12 * Copyright (c) 2014, Intel Corporation.
  13 */
  14
  15#include <linux/device.h>
  16#include <linux/mod_devicetable.h>
  17#include <linux/i2c.h>
  18#include <linux/module.h>
  19#include <linux/acpi.h>
  20#include <linux/regmap.h>
  21
  22#include "bmc150-accel.h"
  23
  24static int bmc150_accel_probe(struct i2c_client *client,
  25                              const struct i2c_device_id *id)
  26{
  27        struct regmap *regmap;
  28        const char *name = NULL;
  29        bool block_supported =
  30                i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
  31                i2c_check_functionality(client->adapter,
  32                                        I2C_FUNC_SMBUS_READ_I2C_BLOCK);
  33        struct acpi_device __maybe_unused *adev;
  34        int ret;
  35
  36        regmap = devm_regmap_init_i2c(client, &bmc150_regmap_conf);
  37        if (IS_ERR(regmap)) {
  38                dev_err(&client->dev, "Failed to initialize i2c regmap\n");
  39                return PTR_ERR(regmap);
  40        }
  41
  42        if (id)
  43                name = id->name;
  44
  45        ret = bmc150_accel_core_probe(&client->dev, regmap, client->irq, name, block_supported);
  46        if (ret)
  47                return ret;
  48
  49        /*
  50         * Some BOSC0200 acpi_devices describe 2 accelerometers in a single ACPI
  51         * device, try instantiating a second i2c_client for an I2cSerialBusV2
  52         * ACPI resource with index 1. The !id check avoids recursion when
  53         * bmc150_accel_probe() gets called for the second client.
  54         */
  55#ifdef CONFIG_ACPI
  56        adev = ACPI_COMPANION(&client->dev);
  57        if (!id && adev && strcmp(acpi_device_hid(adev), "BOSC0200") == 0) {
  58                struct i2c_board_info board_info = {
  59                        .type = "bmc150_accel",
  60                        /*
  61                         * The 2nd accel sits in the base of 2-in-1s. Note this
  62                         * name is static, as there should never be more then 1
  63                         * BOSC0200 ACPI node with 2 accelerometers in it.
  64                         */
  65                        .dev_name = "BOSC0200:base",
  66                        .fwnode = client->dev.fwnode,
  67                        .irq = -ENOENT,
  68                };
  69                struct i2c_client *second_dev;
  70
  71                second_dev = i2c_acpi_new_device(&client->dev, 1, &board_info);
  72                if (!IS_ERR(second_dev))
  73                        bmc150_set_second_device(second_dev);
  74        }
  75#endif
  76
  77        return 0;
  78}
  79
  80static int bmc150_accel_remove(struct i2c_client *client)
  81{
  82        struct i2c_client *second_dev = bmc150_get_second_device(client);
  83
  84        i2c_unregister_device(second_dev);
  85
  86        return bmc150_accel_core_remove(&client->dev);
  87}
  88
  89static const struct acpi_device_id bmc150_accel_acpi_match[] = {
  90        {"BSBA0150",    bmc150},
  91        {"BMC150A",     bmc150},
  92        {"BMI055A",     bmi055},
  93        {"BMA0255",     bma255},
  94        {"BMA250E",     bma250e},
  95        {"BMA222",      bma222},
  96        {"BMA222E",     bma222e},
  97        {"BMA0280",     bma280},
  98        {"BOSC0200"},
  99        { },
 100};
 101MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
 102
 103static const struct i2c_device_id bmc150_accel_id[] = {
 104        {"bmc150_accel",        bmc150},
 105        {"bmi055_accel",        bmi055},
 106        {"bma255",              bma255},
 107        {"bma250e",             bma250e},
 108        {"bma222",              bma222},
 109        {"bma222e",             bma222e},
 110        {"bma280",              bma280},
 111        {}
 112};
 113
 114MODULE_DEVICE_TABLE(i2c, bmc150_accel_id);
 115
 116static const struct of_device_id bmc150_accel_of_match[] = {
 117        { .compatible = "bosch,bmc150_accel" },
 118        { .compatible = "bosch,bmi055_accel" },
 119        { .compatible = "bosch,bma255" },
 120        { .compatible = "bosch,bma250e" },
 121        { .compatible = "bosch,bma222" },
 122        { .compatible = "bosch,bma222e" },
 123        { .compatible = "bosch,bma280" },
 124        { },
 125};
 126MODULE_DEVICE_TABLE(of, bmc150_accel_of_match);
 127
 128static struct i2c_driver bmc150_accel_driver = {
 129        .driver = {
 130                .name   = "bmc150_accel_i2c",
 131                .of_match_table = bmc150_accel_of_match,
 132                .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
 133                .pm     = &bmc150_accel_pm_ops,
 134        },
 135        .probe          = bmc150_accel_probe,
 136        .remove         = bmc150_accel_remove,
 137        .id_table       = bmc150_accel_id,
 138};
 139module_i2c_driver(bmc150_accel_driver);
 140
 141MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
 142MODULE_LICENSE("GPL v2");
 143MODULE_DESCRIPTION("BMC150 I2C accelerometer driver");
 144