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, ®val); 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 ®val); 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"); 246