root/drivers/platform/mellanox/mlxreg-io.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlxreg_io_get_reg
  2. mlxreg_io_attr_show
  3. mlxreg_io_attr_store
  4. mlxreg_io_attr_init
  5. mlxreg_io_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Mellanox register access driver
   4  *
   5  * Copyright (C) 2018 Mellanox Technologies
   6  * Copyright (C) 2018 Vadim Pasternak <vadimp@mellanox.com>
   7  */
   8 
   9 #include <linux/bitops.h>
  10 #include <linux/device.h>
  11 #include <linux/hwmon.h>
  12 #include <linux/hwmon-sysfs.h>
  13 #include <linux/module.h>
  14 #include <linux/of_device.h>
  15 #include <linux/platform_data/mlxreg.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/regmap.h>
  18 
  19 /* Attribute parameters. */
  20 #define MLXREG_IO_ATT_SIZE      10
  21 #define MLXREG_IO_ATT_NUM       48
  22 
  23 /**
  24  * struct mlxreg_io_priv_data - driver's private data:
  25  *
  26  * @pdev: platform device;
  27  * @pdata: platform data;
  28  * @hwmon: hwmon device;
  29  * @mlxreg_io_attr: sysfs attributes array;
  30  * @mlxreg_io_dev_attr: sysfs sensor device attribute array;
  31  * @group: sysfs attribute group;
  32  * @groups: list of sysfs attribute group for hwmon registration;
  33  */
  34 struct mlxreg_io_priv_data {
  35         struct platform_device *pdev;
  36         struct mlxreg_core_platform_data *pdata;
  37         struct device *hwmon;
  38         struct attribute *mlxreg_io_attr[MLXREG_IO_ATT_NUM + 1];
  39         struct sensor_device_attribute mlxreg_io_dev_attr[MLXREG_IO_ATT_NUM];
  40         struct attribute_group group;
  41         const struct attribute_group *groups[2];
  42 };
  43 
  44 static int
  45 mlxreg_io_get_reg(void *regmap, struct mlxreg_core_data *data, u32 in_val,
  46                   bool rw_flag, u32 *regval)
  47 {
  48         int ret;
  49 
  50         ret = regmap_read(regmap, data->reg, regval);
  51         if (ret)
  52                 goto access_error;
  53 
  54         /*
  55          * There are three kinds of attributes: single bit, full register's
  56          * bits and bit sequence. For the first kind field mask indicates which
  57          * bits are not related and field bit is set zero. For the second kind
  58          * field mask is set to zero and field bit is set with all bits one.
  59          * No special handling for such kind of attributes - pass value as is.
  60          * For the third kind, field mask indicates which bits are related and
  61          * field bit is set to the first bit number (from 1 to 32) is the bit
  62          * sequence.
  63          */
  64         if (!data->bit) {
  65                 /* Single bit. */
  66                 if (rw_flag) {
  67                         /* For show: expose effective bit value as 0 or 1. */
  68                         *regval = !!(*regval & ~data->mask);
  69                 } else {
  70                         /* For store: set effective bit value. */
  71                         *regval &= data->mask;
  72                         if (in_val)
  73                                 *regval |= ~data->mask;
  74                 }
  75         } else if (data->mask) {
  76                 /* Bit sequence. */
  77                 if (rw_flag) {
  78                         /* For show: mask and shift right. */
  79                         *regval = ror32(*regval & data->mask, (data->bit - 1));
  80                 } else {
  81                         /* For store: shift to the position and mask. */
  82                         in_val = rol32(in_val, data->bit - 1) & data->mask;
  83                         /* Clear relevant bits and set them to new value. */
  84                         *regval = (*regval & ~data->mask) | in_val;
  85                 }
  86         }
  87 
  88 access_error:
  89         return ret;
  90 }
  91 
  92 static ssize_t
  93 mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr,
  94                     char *buf)
  95 {
  96         struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev);
  97         int index = to_sensor_dev_attr(attr)->index;
  98         struct mlxreg_core_data *data = priv->pdata->data + index;
  99         u32 regval = 0;
 100         int ret;
 101 
 102         ret = mlxreg_io_get_reg(priv->pdata->regmap, data, 0, true, &regval);
 103         if (ret)
 104                 goto access_error;
 105 
 106         return sprintf(buf, "%u\n", regval);
 107 
 108 access_error:
 109         return ret;
 110 }
 111 
 112 static ssize_t
 113 mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr,
 114                      const char *buf, size_t len)
 115 {
 116         struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev);
 117         int index = to_sensor_dev_attr(attr)->index;
 118         struct mlxreg_core_data *data = priv->pdata->data + index;
 119         u32 input_val, regval;
 120         int ret;
 121 
 122         if (len > MLXREG_IO_ATT_SIZE)
 123                 return -EINVAL;
 124 
 125         /* Convert buffer to input value. */
 126         ret = kstrtou32(buf, len, &input_val);
 127         if (ret)
 128                 return ret;
 129 
 130         ret = mlxreg_io_get_reg(priv->pdata->regmap, data, input_val, false,
 131                                 &regval);
 132         if (ret)
 133                 goto access_error;
 134 
 135         ret = regmap_write(priv->pdata->regmap, data->reg, regval);
 136         if (ret)
 137                 goto access_error;
 138 
 139         return len;
 140 
 141 access_error:
 142         dev_err(&priv->pdev->dev, "Bus access error\n");
 143         return ret;
 144 }
 145 
 146 static struct device_attribute mlxreg_io_devattr_rw = {
 147         .show   = mlxreg_io_attr_show,
 148         .store  = mlxreg_io_attr_store,
 149 };
 150 
 151 static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv)
 152 {
 153         int i;
 154 
 155         priv->group.attrs = devm_kcalloc(&priv->pdev->dev,
 156                                          priv->pdata->counter,
 157                                          sizeof(struct attribute *),
 158                                          GFP_KERNEL);
 159         if (!priv->group.attrs)
 160                 return -ENOMEM;
 161 
 162         for (i = 0; i < priv->pdata->counter; i++) {
 163                 priv->mlxreg_io_attr[i] =
 164                                 &priv->mlxreg_io_dev_attr[i].dev_attr.attr;
 165                 memcpy(&priv->mlxreg_io_dev_attr[i].dev_attr,
 166                        &mlxreg_io_devattr_rw, sizeof(struct device_attribute));
 167 
 168                 /* Set attribute name as a label. */
 169                 priv->mlxreg_io_attr[i]->name =
 170                                 devm_kasprintf(&priv->pdev->dev, GFP_KERNEL,
 171                                                priv->pdata->data[i].label);
 172 
 173                 if (!priv->mlxreg_io_attr[i]->name) {
 174                         dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n",
 175                                 i + 1);
 176                         return -ENOMEM;
 177                 }
 178 
 179                 priv->mlxreg_io_dev_attr[i].dev_attr.attr.mode =
 180                                                 priv->pdata->data[i].mode;
 181                 priv->mlxreg_io_dev_attr[i].dev_attr.attr.name =
 182                                         priv->mlxreg_io_attr[i]->name;
 183                 priv->mlxreg_io_dev_attr[i].index = i;
 184                 sysfs_attr_init(&priv->mlxreg_io_dev_attr[i].dev_attr.attr);
 185         }
 186 
 187         priv->group.attrs = priv->mlxreg_io_attr;
 188         priv->groups[0] = &priv->group;
 189         priv->groups[1] = NULL;
 190 
 191         return 0;
 192 }
 193 
 194 static int mlxreg_io_probe(struct platform_device *pdev)
 195 {
 196         struct mlxreg_io_priv_data *priv;
 197         int err;
 198 
 199         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 200         if (!priv)
 201                 return -ENOMEM;
 202 
 203         priv->pdata = dev_get_platdata(&pdev->dev);
 204         if (!priv->pdata) {
 205                 dev_err(&pdev->dev, "Failed to get platform data.\n");
 206                 return -EINVAL;
 207         }
 208 
 209         priv->pdev = pdev;
 210 
 211         err = mlxreg_io_attr_init(priv);
 212         if (err) {
 213                 dev_err(&priv->pdev->dev, "Failed to allocate attributes: %d\n",
 214                         err);
 215                 return err;
 216         }
 217 
 218         priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
 219                                                              "mlxreg_io",
 220                                                               priv,
 221                                                               priv->groups);
 222         if (IS_ERR(priv->hwmon)) {
 223                 dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
 224                         PTR_ERR(priv->hwmon));
 225                 return PTR_ERR(priv->hwmon);
 226         }
 227 
 228         dev_set_drvdata(&pdev->dev, priv);
 229 
 230         return 0;
 231 }
 232 
 233 static struct platform_driver mlxreg_io_driver = {
 234         .driver = {
 235             .name = "mlxreg-io",
 236         },
 237         .probe = mlxreg_io_probe,
 238 };
 239 
 240 module_platform_driver(mlxreg_io_driver);
 241 
 242 MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
 243 MODULE_DESCRIPTION("Mellanox regmap I/O access driver");
 244 MODULE_LICENSE("GPL");
 245 MODULE_ALIAS("platform:mlxreg-io");

/* [<][>][^][v][top][bottom][index][help] */