diff mbox series

[6/6] cap11xx: export major chip settings to sysfs

Message ID 1577647277-8298-7-git-send-email-dev.kurt@vandijck-laurijssen.be (mailing list archive)
State New, archived
Headers show
Series [1/6] cap11xx: set device driver_data | expand

Commit Message

Kurt Van Dijck Dec. 29, 2019, 7:21 p.m. UTC
Signed-off-by: Kurt Van Dijck <dev.kurt@vandijck-laurijssen.be>
---
 drivers/input/keyboard/cap11xx.c | 161 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 161 insertions(+)
diff mbox series

Patch

diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index cdcc89b9..eb68efc 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -346,6 +346,159 @@  static int cap11xx_init_leds(struct device *dev,
 }
 #endif
 
+/* register attribute:
+ * create a simple way to export properties in the register map
+ */
+struct register_attribute {
+	struct device_attribute dev_attr;
+	int reg;
+	int mask;
+	int shift;
+};
+#define to_reg_attr(_dev_attr) container_of((dev_attr), \
+		struct register_attribute, dev_attr)
+#define to_dev_attr(_attr) container_of(attr, struct device_attribute, attr)
+
+static ssize_t show_reg_attr(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct cap11xx_priv *priv = dev_get_drvdata(dev);
+	struct register_attribute *rattr = to_reg_attr(attr);
+	int ret, value;
+
+	ret = regmap_read(priv->regmap, rattr->reg, &value);
+	if (ret < 0)
+		return ret;
+	return sprintf(buf, "0x%02x\n", (value >> rattr->shift) & rattr->mask);
+}
+
+static ssize_t store_reg_attr(struct device *dev, struct device_attribute * attr,
+		const char *buf, size_t len)
+{
+	struct cap11xx_priv *priv = dev_get_drvdata(dev);
+	struct register_attribute *rattr = to_reg_attr(attr);
+	int ret;
+	long value;
+
+	ret = kstrtoul(buf, 0, &value);
+	if (ret)
+		return ret;
+
+	if (value & ~rattr->mask)
+		return -ERANGE;
+
+	ret = regmap_update_bits(priv->regmap, rattr->reg,
+			rattr->mask << rattr->shift, value << rattr->shift);
+	if (ret)
+		return ret;
+	return len;
+}
+
+#define REG_ATTR(_name, _mode, _reg, _nbits, _shift) \
+	struct register_attribute reg_dev_attr_##_name = { \
+		__ATTR(_name, _mode, show_reg_attr, store_reg_attr), \
+		.reg = _reg, \
+		.mask = (1 << (_nbits)) -1, \
+		.shift = _shift, \
+	}
+#define TO_ATTR(_name) (&(reg_dev_attr_##_name).dev_attr.attr)
+
+static REG_ATTR(gain, 0644, CAP11XX_REG_MAIN_CONTROL, 2, 6);
+static REG_ATTR(delta_sense, 0644, CAP11XX_REG_SENSITIVITY_CONTROL, 3, 4);
+static REG_ATTR(base_shift, 0644, CAP11XX_REG_SENSITIVITY_CONTROL, 4, 0);
+static REG_ATTR(dis_dig_noise, 0644, CAP11XX_REG_CONFIG, 1, 5);
+static REG_ATTR(dis_ana_noise, 0644, CAP11XX_REG_CONFIG, 1, 4);
+static REG_ATTR(max_dur_enable, 0644, CAP11XX_REG_CONFIG, 1, 3);
+static REG_ATTR(cs_en, 0644, CAP11XX_REG_SENSOR_ENABLE, 8, 0);
+static REG_ATTR(max_dur, 0644, CAP11XX_REG_SENSOR_CONFIG, 4, 4);
+static REG_ATTR(avg, 0644, CAP11XX_REG_SAMPLING_CONFIG, 3, 4);
+static REG_ATTR(samp_time, 0644, CAP11XX_REG_SAMPLING_CONFIG, 2, 2);
+static REG_ATTR(cycle_time, 0644, CAP11XX_REG_SAMPLING_CONFIG, 2, 0);
+static REG_ATTR(mulkt_blk_en, 0644, CAP11XX_REG_MT_CONFIG, 1, 7);
+static REG_ATTR(b_mult_t, 0644, CAP11XX_REG_MT_CONFIG, 2, 2);
+static REG_ATTR(mtp_en, 0644, CAP11XX_REG_MT_PATTERN_CONFIG, 1, 7);
+static REG_ATTR(mtp_th, 0644, CAP11XX_REG_MT_PATTERN_CONFIG, 2, 2);
+static REG_ATTR(comp_ptrn, 0644, CAP11XX_REG_MT_PATTERN_CONFIG, 1, 1);
+static REG_ATTR(cs_ptrn, 0644, CAP11XX_REG_MT_PATTERN, 8, 0);
+static REG_ATTR(cs_th1, 0644, CAP11XX_REG_SENSOR_THRESH(0), 8, 0);
+static REG_ATTR(cs_th2, 0644, CAP11XX_REG_SENSOR_THRESH(1), 8, 0);
+static REG_ATTR(cs_th3, 0644, CAP11XX_REG_SENSOR_THRESH(2), 8, 0);
+static REG_ATTR(cs_th4, 0644, CAP11XX_REG_SENSOR_THRESH(3), 8, 0);
+static REG_ATTR(cs_th5, 0644, CAP11XX_REG_SENSOR_THRESH(4), 8, 0);
+static REG_ATTR(cs_th6, 0644, CAP11XX_REG_SENSOR_THRESH(5), 8, 0);
+static REG_ATTR(cs_th7, 0644, CAP11XX_REG_SENSOR_THRESH(6), 8, 0);
+static REG_ATTR(cs_th8, 0644, CAP11XX_REG_SENSOR_THRESH(7), 8, 0);
+static REG_ATTR(cs_bn_th, 0644, CAP11XX_REG_SENSOR_NOISE_THRESH, 2, 0);
+static REG_ATTR(cs_led, 0644, CAP11XX_REG_SENSOR_LED_LINK, 8, 0);
+
+static struct attribute *reg_attrs[] = {
+	TO_ATTR(gain),
+	TO_ATTR(delta_sense),
+	TO_ATTR(base_shift),
+	TO_ATTR(dis_dig_noise),
+	TO_ATTR(dis_ana_noise),
+	TO_ATTR(max_dur_enable),
+	TO_ATTR(cs_en),
+	TO_ATTR(max_dur),
+	TO_ATTR(avg),
+	TO_ATTR(samp_time),
+	TO_ATTR(cycle_time),
+	TO_ATTR(mulkt_blk_en),
+	TO_ATTR(b_mult_t),
+	TO_ATTR(mtp_en),
+	TO_ATTR(mtp_th),
+	TO_ATTR(comp_ptrn),
+	TO_ATTR(cs_ptrn),
+	TO_ATTR(cs_th1),
+	TO_ATTR(cs_th2),
+	TO_ATTR(cs_th3),
+	TO_ATTR(cs_th4),
+	TO_ATTR(cs_th5),
+	TO_ATTR(cs_th6),
+	TO_ATTR(cs_th7),
+	TO_ATTR(cs_th8),
+	TO_ATTR(cs_bn_th),
+	TO_ATTR(cs_led),
+	NULL,
+};
+
+static const struct attribute_group reg_attr_group = {
+	.name = "reg",
+	.attrs = reg_attrs,
+};
+
+/* load register properties from OF */
+static int cap11xx_load_regs_from_of(struct device *dev)
+{
+	struct cap11xx_priv *priv = dev_get_drvdata(dev);
+	struct attribute **attr;
+	struct register_attribute *rattr;
+	char name[32];
+	int ret, value;
+
+	for (attr = reg_attrs; *attr; ++attr) {
+		rattr = to_reg_attr(to_dev_attr(*attr));
+
+		sprintf(name, "reg,%s", rattr->dev_attr.attr.name);
+		ret = of_property_read_u32(dev->of_node, name, &value);
+		if (ret)
+			continue;
+		if (value & ~rattr->mask) {
+			dev_warn(dev, "of %s: value %u, max %u\n",
+					name, value, rattr->mask);
+			continue;
+		}
+		ret = regmap_update_bits(priv->regmap, rattr->reg,
+				rattr->mask << rattr->shift,
+				value << rattr->shift);
+		if (ret) {
+			dev_err(dev, "of %s, regmap returned %i\n", name, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
 static int cap11xx_i2c_remove(struct i2c_client *i2c_client)
 {
 	struct cap11xx_priv *priv = i2c_get_clientdata(i2c_client);
@@ -430,6 +583,10 @@  static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
 			return error;
 	}
 
+	error = cap11xx_load_regs_from_of(dev);
+	if (error)
+		return error;
+
 	/* Provide some useful defaults */
 	for (i = 0; i < cap->num_channels; i++)
 		priv->keycodes[i] = KEY_A + i;
@@ -491,6 +648,10 @@  static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
 	if (error)
 		return error;
 
+	error = devm_device_add_group(dev, &reg_attr_group);
+	if (error)
+		return error;
+
 	irq = irq_of_parse_and_map(node, 0);
 	if (!irq) {
 		if (!of_property_read_bool(node, "linux,irq-poll")) {