blob: 0b8b3fc29b0ae87962da89621bac22a345796256 [file] [log] [blame]
/*
* Copyright (C) 2012-2017 InvenSense, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
#include <linux/export.h>
#include <linux/iio/imu/mpu.h>
#include "inv_mpu_dts.h"
#include "inv_mpu_iio.h"
#ifdef CONFIG_OF
static int inv_mpu_power_on(struct mpu_platform_data *pdata)
{
int err;
if (!IS_ERR(pdata->vdd_ana)) {
err = regulator_enable(pdata->vdd_ana);
if (err)
return err;
}
if (!IS_ERR(pdata->vdd_i2c)) {
err = regulator_enable(pdata->vdd_i2c);
if (err)
goto error_disable_vdd_ana;
}
return 0;
error_disable_vdd_ana:
regulator_disable(pdata->vdd_ana);
return err;
}
static int inv_mpu_power_off(struct mpu_platform_data *pdata)
{
if (!IS_ERR(pdata->vdd_ana))
regulator_disable(pdata->vdd_ana);
if (!IS_ERR(pdata->vdd_i2c))
regulator_disable(pdata->vdd_i2c);
return 0;
}
static int inv_parse_orientation_matrix(struct device *dev, s8 *orient)
{
int rc, i;
struct device_node *np = dev->of_node;
u32 temp_val, temp_val2;
for (i = 0; i < 9; i++)
orient[i] = 0;
/* parsing axis x orientation matrix */
rc = of_property_read_u32(np, "axis_map_x", &temp_val);
if (rc) {
dev_err(dev, "Unable to read axis_map_x\n");
return rc;
}
rc = of_property_read_u32(np, "negate_x", &temp_val2);
if (rc) {
dev_err(dev, "Unable to read negate_x\n");
return rc;
}
if (temp_val2)
orient[temp_val] = -1;
else
orient[temp_val] = 1;
/* parsing axis y orientation matrix */
rc = of_property_read_u32(np, "axis_map_y", &temp_val);
if (rc) {
dev_err(dev, "Unable to read axis_map_y\n");
return rc;
}
rc = of_property_read_u32(np, "negate_y", &temp_val2);
if (rc) {
dev_err(dev, "Unable to read negate_y\n");
return rc;
}
if (temp_val2)
orient[3 + temp_val] = -1;
else
orient[3 + temp_val] = 1;
/* parsing axis z orientation matrix */
rc = of_property_read_u32(np, "axis_map_z", &temp_val);
if (rc) {
dev_err(dev, "Unable to read axis_map_z\n");
return rc;
}
rc = of_property_read_u32(np, "negate_z", &temp_val2);
if (rc) {
dev_err(dev, "Unable to read negate_z\n");
return rc;
}
if (temp_val2)
orient[6 + temp_val] = -1;
else
orient[6 + temp_val] = 1;
return 0;
}
static int inv_parse_secondary_orientation_matrix(struct device *dev,
s8 *orient)
{
int rc, i;
struct device_node *np = dev->of_node;
u32 temp_val, temp_val2;
for (i = 0; i < 9; i++)
orient[i] = 0;
/* parsing axis x orientation matrix */
rc = of_property_read_u32(np, "inven,secondary_axis_map_x", &temp_val);
if (rc) {
dev_err(dev, "Unable to read secondary axis_map_x\n");
return rc;
}
rc = of_property_read_u32(np, "inven,secondary_negate_x", &temp_val2);
if (rc) {
dev_err(dev, "Unable to read secondary negate_x\n");
return rc;
}
if (temp_val2)
orient[temp_val] = -1;
else
orient[temp_val] = 1;
/* parsing axis y orientation matrix */
rc = of_property_read_u32(np, "inven,secondary_axis_map_y", &temp_val);
if (rc) {
dev_err(dev, "Unable to read secondary axis_map_y\n");
return rc;
}
rc = of_property_read_u32(np, "inven,secondary_negate_y", &temp_val2);
if (rc) {
dev_err(dev, "Unable to read secondary negate_y\n");
return rc;
}
if (temp_val2)
orient[3 + temp_val] = -1;
else
orient[3 + temp_val] = 1;
/* parsing axis z orientation matrix */
rc = of_property_read_u32(np, "inven,secondary_axis_map_z", &temp_val);
if (rc) {
dev_err(dev, "Unable to read secondary axis_map_z\n");
return rc;
}
rc = of_property_read_u32(np, "inven,secondary_negate_z", &temp_val2);
if (rc) {
dev_err(dev, "Unable to read secondary negate_z\n");
return rc;
}
if (temp_val2)
orient[6 + temp_val] = -1;
else
orient[6 + temp_val] = 1;
return 0;
}
static int inv_parse_secondary(struct device *dev,
struct mpu_platform_data *pdata)
{
int rc;
struct device_node *np = dev->of_node;
u32 temp_val;
const char *name;
if (of_property_read_string(np, "inven,secondary_type", &name)) {
dev_err(dev, "Missing secondary type.\n");
return -EINVAL;
}
if (!strcmp(name, "compass")) {
pdata->sec_slave_type = SECONDARY_SLAVE_TYPE_COMPASS;
} else if (!strcmp(name, "none")) {
pdata->sec_slave_type = SECONDARY_SLAVE_TYPE_NONE;
return 0;
} else {
return -EINVAL;
}
if (of_property_read_string(np, "inven,secondary_name", &name)) {
dev_err(dev, "Missing secondary name.\n");
return -EINVAL;
}
if (!strcmp(name, "ak8963"))
pdata->sec_slave_id = COMPASS_ID_AK8963;
else if (!strcmp(name, "ak8975"))
pdata->sec_slave_id = COMPASS_ID_AK8975;
else if (!strcmp(name, "ak8972"))
pdata->sec_slave_id = COMPASS_ID_AK8972;
else if (!strcmp(name, "ak09911"))
pdata->sec_slave_id = COMPASS_ID_AK09911;
else if (!strcmp(name, "ak09912"))
pdata->sec_slave_id = COMPASS_ID_AK09912;
else if (!strcmp(name, "ak09916"))
pdata->sec_slave_id = COMPASS_ID_AK09916;
else
return -EINVAL;
rc = of_property_read_u32(np, "inven,secondary_reg", &temp_val);
if (rc) {
dev_err(dev, "Unable to read secondary register\n");
return rc;
}
pdata->secondary_i2c_addr = temp_val;
rc = inv_parse_secondary_orientation_matrix(dev,
pdata->
secondary_orientation);
return rc;
}
static int inv_parse_aux(struct device *dev, struct mpu_platform_data *pdata)
{
int rc;
struct device_node *np = dev->of_node;
u32 temp_val;
const char *name;
if (of_property_read_string(np, "inven,aux_type", &name)) {
dev_err(dev, "Missing aux type.\n");
return -EINVAL;
}
if (!strcmp(name, "pressure")) {
pdata->aux_slave_type = SECONDARY_SLAVE_TYPE_PRESSURE;
} else if (!strcmp(name, "none")) {
pdata->aux_slave_type = SECONDARY_SLAVE_TYPE_NONE;
return 0;
} else {
return -EINVAL;
}
if (of_property_read_string(np, "inven,aux_name", &name)) {
dev_err(dev, "Missing aux name.\n");
return -EINVAL;
}
if (!strcmp(name, "bmp280"))
pdata->aux_slave_id = PRESSURE_ID_BMP280;
else
return -EINVAL;
rc = of_property_read_u32(np, "inven,aux_reg", &temp_val);
if (rc) {
dev_err(dev, "Unable to read aux register\n");
return rc;
}
pdata->aux_i2c_addr = temp_val;
return 0;
}
static int inv_parse_readonly_secondary(struct device *dev,
struct mpu_platform_data *pdata)
{
int rc;
struct device_node *np = dev->of_node;
u32 temp_val;
const char *name;
if (of_property_read_string(np, "inven,read_only_slave_type", &name)) {
dev_err(dev, "Missing read only slave type type.\n");
return -EINVAL;
}
if (!strcmp(name, "als")) {
pdata->read_only_slave_type = SECONDARY_SLAVE_TYPE_ALS;
} else if (!strcmp(name, "none")) {
pdata->read_only_slave_type = SECONDARY_SLAVE_TYPE_NONE;
return 0;
} else {
return -EINVAL;
}
if (of_property_read_string(np, "inven,read_only_slave_name", &name)) {
dev_err(dev, "Missing read only slave type name.\n");
return -EINVAL;
}
if (!strcmp(name, "apds9930"))
pdata->read_only_slave_id = ALS_ID_APDS_9930;
else
return -EINVAL;
rc = of_property_read_u32(np, "inven,read_only_slave_reg", &temp_val);
if (rc) {
dev_err(dev, "Unable to read read only slave reg register\n");
return rc;
}
pdata->read_only_i2c_addr = temp_val;
return 0;
}
int invensense_mpu_parse_dt(struct device *dev, struct mpu_platform_data *pdata)
{
int rc;
rc = inv_parse_orientation_matrix(dev, pdata->orientation);
if (rc)
return rc;
rc = inv_parse_secondary(dev, pdata);
if (rc)
return rc;
inv_parse_aux(dev, pdata);
inv_parse_readonly_secondary(dev, pdata);
pdata->vdd_ana = regulator_get(dev, "inven,vdd_ana");
if (IS_ERR(pdata->vdd_ana)) {
rc = PTR_ERR(pdata->vdd_ana);
dev_warn(dev, "regulator get failed vdd_ana-supply rc=%d\n", rc);
}
pdata->vdd_i2c = regulator_get(dev, "inven,vcc_i2c");
if (IS_ERR(pdata->vdd_i2c)) {
rc = PTR_ERR(pdata->vdd_i2c);
dev_warn(dev, "regulator get failed vcc-i2c-supply rc=%d\n", rc);
}
pdata->power_on = inv_mpu_power_on;
pdata->power_off = inv_mpu_power_off;
dev_dbg(dev, "parse dt complete\n");
return 0;
}
EXPORT_SYMBOL_GPL(invensense_mpu_parse_dt);
#endif /* CONFIG_OF */