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