summaryrefslogtreecommitdiff
path: root/drivers/platform/mellanox/mlxreg-io.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/mellanox/mlxreg-io.c')
-rw-r--r--drivers/platform/mellanox/mlxreg-io.c73
1 files changed, 57 insertions, 16 deletions
diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c
index acfaf64ffde6..97fefe6c38d1 100644
--- a/drivers/platform/mellanox/mlxreg-io.c
+++ b/drivers/platform/mellanox/mlxreg-io.c
@@ -11,14 +11,13 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/platform_data/mlxreg.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* Attribute parameters. */
#define MLXREG_IO_ATT_SIZE 10
-#define MLXREG_IO_ATT_NUM 48
+#define MLXREG_IO_ATT_NUM 96
/**
* struct mlxreg_io_priv_data - driver's private data:
@@ -30,6 +29,8 @@
* @mlxreg_io_dev_attr: sysfs sensor device attribute array;
* @group: sysfs attribute group;
* @groups: list of sysfs attribute group for hwmon registration;
+ * @regsize: size of a register value;
+ * @io_lock: user access locking;
*/
struct mlxreg_io_priv_data {
struct platform_device *pdev;
@@ -39,27 +40,31 @@ struct mlxreg_io_priv_data {
struct sensor_device_attribute mlxreg_io_dev_attr[MLXREG_IO_ATT_NUM];
struct attribute_group group;
const struct attribute_group *groups[2];
+ int regsize;
+ struct mutex io_lock; /* Protects user access. */
};
static int
mlxreg_io_get_reg(void *regmap, struct mlxreg_core_data *data, u32 in_val,
- bool rw_flag, u32 *regval)
+ bool rw_flag, int regsize, u32 *regval)
{
- int ret;
+ int i, val, ret;
ret = regmap_read(regmap, data->reg, regval);
if (ret)
goto access_error;
/*
- * There are three kinds of attributes: single bit, full register's
- * bits and bit sequence. For the first kind field mask indicates which
- * bits are not related and field bit is set zero. For the second kind
- * field mask is set to zero and field bit is set with all bits one.
- * No special handling for such kind of attributes - pass value as is.
- * For the third kind, field mask indicates which bits are related and
- * field bit is set to the first bit number (from 1 to 32) is the bit
- * sequence.
+ * There are four kinds of attributes: single bit, full register's
+ * bits, bit sequence, bits in few registers For the first kind field
+ * mask indicates which bits are not related and field bit is set zero.
+ * For the second kind field mask is set to zero and field bit is set
+ * with all bits one. No special handling for such kind of attributes -
+ * pass value as is. For the third kind, the field mask indicates which
+ * bits are related and the field bit is set to the first bit number
+ * (from 1 to 32) is the bit sequence. For the fourth kind - the number
+ * of registers which should be read for getting an attribute are
+ * specified through 'data->regnum' field.
*/
if (!data->bit) {
/* Single bit. */
@@ -83,6 +88,19 @@ mlxreg_io_get_reg(void *regmap, struct mlxreg_core_data *data, u32 in_val,
/* Clear relevant bits and set them to new value. */
*regval = (*regval & ~data->mask) | in_val;
}
+ } else {
+ /*
+ * Some attributes could occupied few registers in case regmap
+ * bit size is 8 or 16. Compose such attributes from 'regnum'
+ * registers. Such attributes contain read-only data.
+ */
+ for (i = 1; i < data->regnum; i++) {
+ ret = regmap_read(regmap, data->reg + i, &val);
+ if (ret)
+ goto access_error;
+
+ *regval |= rol32(val, regsize * i * 8);
+ }
}
access_error:
@@ -99,13 +117,19 @@ mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr,
u32 regval = 0;
int ret;
- ret = mlxreg_io_get_reg(priv->pdata->regmap, data, 0, true, &regval);
+ mutex_lock(&priv->io_lock);
+
+ ret = mlxreg_io_get_reg(priv->pdata->regmap, data, 0, true,
+ priv->regsize, &regval);
if (ret)
goto access_error;
- return sprintf(buf, "%u\n", regval);
+ mutex_unlock(&priv->io_lock);
+
+ return sysfs_emit(buf, "%u\n", regval);
access_error:
+ mutex_unlock(&priv->io_lock);
return ret;
}
@@ -123,12 +147,14 @@ mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr,
return -EINVAL;
/* Convert buffer to input value. */
- ret = kstrtou32(buf, len, &input_val);
+ ret = kstrtou32(buf, 0, &input_val);
if (ret)
return ret;
+ mutex_lock(&priv->io_lock);
+
ret = mlxreg_io_get_reg(priv->pdata->regmap, data, input_val, false,
- &regval);
+ priv->regsize, &regval);
if (ret)
goto access_error;
@@ -136,9 +162,12 @@ mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr,
if (ret)
goto access_error;
+ mutex_unlock(&priv->io_lock);
+
return len;
access_error:
+ mutex_unlock(&priv->io_lock);
dev_err(&priv->pdev->dev, "Bus access error\n");
return ret;
}
@@ -207,6 +236,9 @@ static int mlxreg_io_probe(struct platform_device *pdev)
}
priv->pdev = pdev;
+ priv->regsize = regmap_get_val_bytes(priv->pdata->regmap);
+ if (priv->regsize < 0)
+ return priv->regsize;
err = mlxreg_io_attr_init(priv);
if (err) {
@@ -225,16 +257,25 @@ static int mlxreg_io_probe(struct platform_device *pdev)
return PTR_ERR(priv->hwmon);
}
+ mutex_init(&priv->io_lock);
dev_set_drvdata(&pdev->dev, priv);
return 0;
}
+static void mlxreg_io_remove(struct platform_device *pdev)
+{
+ struct mlxreg_io_priv_data *priv = dev_get_drvdata(&pdev->dev);
+
+ mutex_destroy(&priv->io_lock);
+}
+
static struct platform_driver mlxreg_io_driver = {
.driver = {
.name = "mlxreg-io",
},
.probe = mlxreg_io_probe,
+ .remove = mlxreg_io_remove,
};
module_platform_driver(mlxreg_io_driver);