Compare commits
4 commits
f3a72db738
...
1c885459bb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c885459bb | ||
|
|
51baa87931 | ||
|
|
0adb30c4e3 | ||
|
|
12bbdac5a5 |
4 changed files with 1087 additions and 15 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -173,15 +173,69 @@ static void bmc150_acpi_dual_accel_remove(struct i2c_client *client) {}
|
|||
|
||||
static int bmc150_accel_probe(struct i2c_client *client)
|
||||
{
|
||||
int ret;
|
||||
u8 chip_id_first[4];
|
||||
enum bmc150_device_type dev_type = BMC150;
|
||||
const struct i2c_device_id *id = i2c_client_get_device_id(client);
|
||||
struct regmap *regmap;
|
||||
const char *name = NULL;
|
||||
enum bmc150_type type = BOSCH_UNKNOWN;
|
||||
bool block_supported =
|
||||
bool block_supported = false;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(client, 0x00, 4, &chip_id_first[0]);
|
||||
if (ret != 4) {
|
||||
dev_err(&client->dev, "error in i2c_smbus_read_i2c_block_data = %d: reg = 0x%02x", (int)ret, 0x00);
|
||||
goto bmi150_old_probe;
|
||||
}
|
||||
|
||||
if (chip_id_first[2] != 0x43) {
|
||||
dev_err(&client->dev, "chip is not a bmi323.");
|
||||
} else {
|
||||
dev_err(&client->dev, "chip is a bmi323!");
|
||||
dev_type = BMI323;
|
||||
}
|
||||
|
||||
if (dev_type == BMI323) {
|
||||
/*dev_warn*/ dev_err(&client->dev, "bmc323: the bmc150 is for sure a bmc323...\n");
|
||||
|
||||
struct iio_dev *indio_dev = devm_iio_device_alloc(&client->dev, sizeof(struct bmc150_accel_data));
|
||||
if (!indio_dev) {
|
||||
dev_err(&client->dev, "bmc323: out of memory\n");
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&client->dev, indio_dev);
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
|
||||
struct bmi323_private_data* bmi323_data = &data->bmi323;
|
||||
bmi323_data->i2c_client = client;
|
||||
bmi323_data->spi_client = NULL;
|
||||
bmi323_data->irq = client->irq;
|
||||
|
||||
ret = bmi323_chip_rst(bmi323_data);
|
||||
if (ret != 0) {
|
||||
dev_err(&client->dev, "bmc323: error issuing the chip reset: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*dev_info*/ dev_err(&client->dev, "bmc323: chip rst success\n");
|
||||
|
||||
ret = bmi323_iio_init(indio_dev);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bmi150_old_probe:
|
||||
dev_err(&client->dev, "executing the normal procedure for a bmc150...");
|
||||
|
||||
block_supported =
|
||||
i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
|
||||
i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK);
|
||||
int ret;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &bmc150_regmap_conf);
|
||||
if (IS_ERR(regmap)) {
|
||||
|
|
@ -196,8 +250,9 @@ static int bmc150_accel_probe(struct i2c_client *client)
|
|||
|
||||
ret = bmc150_accel_core_probe(&client->dev, regmap, client->irq,
|
||||
type, name, block_supported);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The !id check avoids recursion when probe() gets called
|
||||
|
|
@ -211,6 +266,24 @@ static int bmc150_accel_probe(struct i2c_client *client)
|
|||
|
||||
static void bmc150_accel_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(&client->dev);
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (data->dev_type == BMI323) {
|
||||
/*dev_info*/ dev_err(&client->dev, "bmc323 removing driver...\n");
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
/*dev_info*/ dev_err(&client->dev, "bmc323 deallocating driver storage...\n");
|
||||
|
||||
iio_device_free(indio_dev);
|
||||
|
||||
/*dev_info*/ dev_err(&client->dev, "bmc323 removal done.\n");
|
||||
|
||||
// TODO: create and call functions for bmi323
|
||||
return;
|
||||
}
|
||||
|
||||
bmc150_acpi_dual_accel_remove(client);
|
||||
|
||||
bmc150_accel_core_remove(&client->dev);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
struct regmap;
|
||||
struct i2c_client;
|
||||
struct bmc150_accel_chip_info;
|
||||
|
|
@ -34,6 +37,11 @@ struct bmc150_accel_interrupt {
|
|||
atomic_t users;
|
||||
};
|
||||
|
||||
enum bmc150_device_type {
|
||||
BMC150,
|
||||
BMI323,
|
||||
};
|
||||
|
||||
struct bmc150_accel_trigger {
|
||||
struct bmc150_accel_data *data;
|
||||
struct iio_trigger *indio_trig;
|
||||
|
|
@ -55,6 +63,17 @@ enum bmc150_accel_trigger_id {
|
|||
BMC150_ACCEL_TRIGGERS,
|
||||
};
|
||||
|
||||
#define BMI323_FLAGS_RESET_FAILED 0x00000001U
|
||||
|
||||
struct bmi323_private_data {
|
||||
struct i2c_client* i2c_client;
|
||||
struct spi_device* spi_client;
|
||||
struct device* dev; // pointer at i2c_client->dev or spi_client->dev
|
||||
struct mutex mutex;
|
||||
int irq;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct bmc150_accel_data {
|
||||
struct regmap *regmap;
|
||||
struct regulator_bulk_data regulators[2];
|
||||
|
|
@ -83,7 +102,29 @@ struct bmc150_accel_data {
|
|||
void (*resume_callback)(struct device *dev);
|
||||
struct delayed_work resume_work;
|
||||
struct iio_mount_matrix orientation;
|
||||
};
|
||||
enum bmc150_device_type dev_type;
|
||||
struct bmi323_private_data bmi323;
|
||||
};
|
||||
|
||||
#define BCM150_BMI323_SOFT_RESET_REG 0x7E
|
||||
#define BCM150_BMI323_SOFT_RESET_VAL 0xDEAF
|
||||
|
||||
|
||||
|
||||
int bmc323_write_u16(struct bmi323_private_data *bmi323, u8 in_reg, u16 in_value);
|
||||
int bmc323_read_s16(struct bmi323_private_data *bmi323, u8 in_reg, s16* out_value);
|
||||
int bmc323_read_u16(struct bmi323_private_data *bmi323, u8 in_reg, u16* out_value);
|
||||
int bmi323_chip_check(struct bmi323_private_data *bmi323);
|
||||
int bmi323_chip_rst(struct bmi323_private_data *bmi323);
|
||||
|
||||
/**
|
||||
* This function MUST be called in probe and is responsible for registering the userspace sysfs.
|
||||
*
|
||||
* The indio_dev MUST have been allocated but not registered. This function will perform userspace registration.
|
||||
*
|
||||
* @param indio_dev the industrual io device already allocated but not yet registered
|
||||
*/
|
||||
int bmi323_iio_init(struct iio_dev *indio_dev);
|
||||
|
||||
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
||||
enum bmc150_type type, const char *name,
|
||||
|
|
|
|||
|
|
@ -1500,17 +1500,26 @@ static DEVICE_ATTR_RW(current_timestamp_clock);
|
|||
|
||||
static int iio_device_register_sysfs(struct iio_dev *indio_dev)
|
||||
{
|
||||
dev_err(NULL, " begin to_iio_dev_opaque");
|
||||
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
|
||||
int i, ret = 0, attrcount, attrn, attrcount_orig = 0;
|
||||
struct iio_dev_attr *p;
|
||||
struct attribute **attr, *clk = NULL;
|
||||
dev_err(NULL, " end to_iio_dev_opaque");
|
||||
|
||||
/* First count elements in any existing group */
|
||||
dev_err(NULL, " begin if (indio_dev->info->attrs)");
|
||||
if (indio_dev->info->attrs) {
|
||||
dev_err(NULL, " begin attr = indio_dev->info->attrs->attrs");
|
||||
attr = indio_dev->info->attrs->attrs;
|
||||
dev_err(NULL, " end attr = indio_dev->info->attrs->attrs");
|
||||
|
||||
dev_err(NULL, " begin while (*attr++ != NULL)");
|
||||
while (*attr++ != NULL)
|
||||
attrcount_orig++;
|
||||
dev_err(NULL, " end while (*attr++ != NULL)");
|
||||
}
|
||||
dev_err(NULL, " begin end (indio_dev->info->attrs)");
|
||||
attrcount = attrcount_orig;
|
||||
/*
|
||||
* New channel registration method - relies on the fact a group does
|
||||
|
|
@ -1524,7 +1533,9 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
|
|||
if (chan->type == IIO_TIMESTAMP)
|
||||
clk = &dev_attr_current_timestamp_clock.attr;
|
||||
|
||||
dev_err(NULL, " begin iio_device_add_channel_sysfs #%d/%d", i, (int)indio_dev->num_channels);
|
||||
ret = iio_device_add_channel_sysfs(indio_dev, chan);
|
||||
dev_err(NULL, " end iio_device_add_channel_sysfs #%d/%d", i, (int)indio_dev->num_channels);
|
||||
if (ret < 0)
|
||||
goto error_clear_attrs;
|
||||
attrcount += ret;
|
||||
|
|
@ -1540,20 +1551,24 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
|
|||
if (clk)
|
||||
attrcount++;
|
||||
|
||||
dev_err(NULL, " begin kcalloc");
|
||||
iio_dev_opaque->chan_attr_group.attrs =
|
||||
kcalloc(attrcount + 1,
|
||||
sizeof(iio_dev_opaque->chan_attr_group.attrs[0]),
|
||||
GFP_KERNEL);
|
||||
dev_err(NULL, " end kcalloc");
|
||||
if (iio_dev_opaque->chan_attr_group.attrs == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_clear_attrs;
|
||||
}
|
||||
/* Copy across original attributes, and point to original binary attributes */
|
||||
if (indio_dev->info->attrs) {
|
||||
dev_err(NULL, " begin memcpy");
|
||||
memcpy(iio_dev_opaque->chan_attr_group.attrs,
|
||||
indio_dev->info->attrs->attrs,
|
||||
sizeof(iio_dev_opaque->chan_attr_group.attrs[0])
|
||||
*attrcount_orig);
|
||||
dev_err(NULL, " end memcpy");
|
||||
iio_dev_opaque->chan_attr_group.is_visible =
|
||||
indio_dev->info->attrs->is_visible;
|
||||
iio_dev_opaque->chan_attr_group.bin_attrs =
|
||||
|
|
@ -1561,8 +1576,10 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
|
|||
}
|
||||
attrn = attrcount_orig;
|
||||
/* Add all elements from the list. */
|
||||
dev_err(NULL, " begin list_for_each_entry");
|
||||
list_for_each_entry(p, &iio_dev_opaque->channel_attr_list, l)
|
||||
iio_dev_opaque->chan_attr_group.attrs[attrn++] = &p->dev_attr.attr;
|
||||
dev_err(NULL, " end list_for_each_entry");
|
||||
if (indio_dev->name)
|
||||
iio_dev_opaque->chan_attr_group.attrs[attrn++] = &dev_attr_name.attr;
|
||||
if (indio_dev->label)
|
||||
|
|
@ -1570,15 +1587,19 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
|
|||
if (clk)
|
||||
iio_dev_opaque->chan_attr_group.attrs[attrn++] = clk;
|
||||
|
||||
dev_err(NULL, " begin iio_device_register_sysfs_group");
|
||||
ret = iio_device_register_sysfs_group(indio_dev,
|
||||
&iio_dev_opaque->chan_attr_group);
|
||||
dev_err(NULL, " end iio_device_register_sysfs_group");
|
||||
if (ret)
|
||||
goto error_clear_attrs;
|
||||
|
||||
return 0;
|
||||
|
||||
error_clear_attrs:
|
||||
dev_err(NULL, " ERROR HERE: begin iio_free_chan_devattr_list");
|
||||
iio_free_chan_devattr_list(&iio_dev_opaque->channel_attr_list);
|
||||
dev_err(NULL, " ERROR HERE: end iio_free_chan_devattr_list");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1856,8 +1877,8 @@ static int iio_check_unique_scan_index(struct iio_dev *indio_dev)
|
|||
for (j = i + 1; j < indio_dev->num_channels; j++)
|
||||
if (channels[i].scan_index == channels[j].scan_index) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"Duplicate scan index %d\n",
|
||||
channels[i].scan_index);
|
||||
"Duplicate scan index %d at elements (%d, %d)\n",
|
||||
channels[i].scan_index, i , j);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
@ -1887,6 +1908,7 @@ static const struct iio_buffer_setup_ops noop_ring_setup_ops;
|
|||
|
||||
int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
|
||||
{
|
||||
dev_err(NULL, "begin __iio_device_register\n");
|
||||
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
|
||||
struct fwnode_handle *fwnode = NULL;
|
||||
int ret;
|
||||
|
|
@ -1894,6 +1916,8 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
|
|||
if (!indio_dev->info)
|
||||
return -EINVAL;
|
||||
|
||||
dev_err(NULL, " indio_dev->info is NOT NULL\n");
|
||||
|
||||
iio_dev_opaque->driver_module = this_mod;
|
||||
|
||||
/* If the calling driver did not initialize firmware node, do it here */
|
||||
|
|
@ -1902,60 +1926,95 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
|
|||
/* The default dummy IIO device has no parent */
|
||||
else if (indio_dev->dev.parent)
|
||||
fwnode = dev_fwnode(indio_dev->dev.parent);
|
||||
|
||||
dev_err(NULL, " begin device_set_node\n");
|
||||
device_set_node(&indio_dev->dev, fwnode);
|
||||
dev_err(NULL, " end device_set_node\n");
|
||||
|
||||
dev_err(NULL, " begin fwnode_property_read_string\n");
|
||||
fwnode_property_read_string(fwnode, "label", &indio_dev->label);
|
||||
dev_err(NULL, " end fwnode_property_read_string\n");
|
||||
|
||||
dev_err(NULL, " begin iio_check_unique_scan_index\n");
|
||||
ret = iio_check_unique_scan_index(indio_dev);
|
||||
dev_err(NULL, " end iio_check_unique_scan_index\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_err(NULL, " begin iio_check_extended_name\n");
|
||||
ret = iio_check_extended_name(indio_dev);
|
||||
dev_err(NULL, " end iio_check_extended_name\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_err(NULL, " begin iio_device_register_debugfs\n");
|
||||
iio_device_register_debugfs(indio_dev);
|
||||
dev_err(NULL, " end iio_device_register_debugfs\n");
|
||||
|
||||
dev_err(NULL, " begin iio_buffers_alloc_sysfs_and_mask\n");
|
||||
ret = iio_buffers_alloc_sysfs_and_mask(indio_dev);
|
||||
dev_err(NULL, " end iio_buffers_alloc_sysfs_and_mask\n");
|
||||
if (ret) {
|
||||
dev_err(indio_dev->dev.parent,
|
||||
"Failed to create buffer sysfs interfaces\n");
|
||||
goto error_unreg_debugfs;
|
||||
}
|
||||
|
||||
dev_err(NULL, " begin iio_device_register_sysfs\n");
|
||||
ret = iio_device_register_sysfs(indio_dev);
|
||||
dev_err(NULL, " end iio_device_register_sysfs\n");
|
||||
if (ret) {
|
||||
dev_err(indio_dev->dev.parent,
|
||||
"Failed to register sysfs interfaces\n");
|
||||
goto error_buffer_free_sysfs;
|
||||
}
|
||||
|
||||
dev_err(NULL, " begin iio_device_register_eventset\n");
|
||||
ret = iio_device_register_eventset(indio_dev);
|
||||
dev_err(NULL, " end iio_device_register_eventset\n");
|
||||
if (ret) {
|
||||
dev_err(indio_dev->dev.parent,
|
||||
"Failed to register event set\n");
|
||||
goto error_free_sysfs;
|
||||
}
|
||||
if (indio_dev->modes & INDIO_ALL_TRIGGERED_MODES)
|
||||
if (indio_dev->modes & INDIO_ALL_TRIGGERED_MODES) {
|
||||
dev_err(NULL, " begin iio_device_register_trigger_consumer\n");
|
||||
iio_device_register_trigger_consumer(indio_dev);
|
||||
dev_err(NULL, " end iio_device_register_trigger_consumer\n");
|
||||
} else {
|
||||
dev_err(NULL, " no iio_device_register_trigger_consumer performed\n");
|
||||
}
|
||||
|
||||
if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) &&
|
||||
indio_dev->setup_ops == NULL)
|
||||
indio_dev->setup_ops = &noop_ring_setup_ops;
|
||||
|
||||
if (iio_dev_opaque->attached_buffers_cnt)
|
||||
if (iio_dev_opaque->attached_buffers_cnt) {
|
||||
dev_err(NULL, " begin cdev_init 1\n");
|
||||
cdev_init(&iio_dev_opaque->chrdev, &iio_buffer_fileops);
|
||||
else if (iio_dev_opaque->event_interface)
|
||||
dev_err(NULL, " end cdev_init 1\n");
|
||||
}
|
||||
else if (iio_dev_opaque->event_interface) {
|
||||
dev_err(NULL, " begin cdev_init 2\n");
|
||||
cdev_init(&iio_dev_opaque->chrdev, &iio_event_fileops);
|
||||
dev_err(NULL, " end cdev_init 1\n");
|
||||
} else {
|
||||
dev_err(NULL, " no cdev_init\n");
|
||||
}
|
||||
|
||||
if (iio_dev_opaque->attached_buffers_cnt || iio_dev_opaque->event_interface) {
|
||||
dev_err(NULL, " begin MKDEV\n");
|
||||
indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), iio_dev_opaque->id);
|
||||
iio_dev_opaque->chrdev.owner = this_mod;
|
||||
dev_err(NULL, " end MKDEV\n");
|
||||
}
|
||||
|
||||
/* assign device groups now; they should be all registered now */
|
||||
indio_dev->dev.groups = iio_dev_opaque->groups;
|
||||
|
||||
dev_err(NULL, " begin cdev_device_add\n");
|
||||
ret = cdev_device_add(&iio_dev_opaque->chrdev, &indio_dev->dev);
|
||||
dev_err(NULL, " end cdev_device_add\n");
|
||||
if (ret < 0)
|
||||
goto error_unreg_eventset;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue