* [PATCH 2/6] cap11xx: support cap1208
2019-12-29 19:21 [RFC] input: cap11xx: plasma globe proof Kurt Van Dijck
2019-12-29 19:21 ` [PATCH 1/6] cap11xx: set device driver_data Kurt Van Dijck
@ 2019-12-29 19:21 ` Kurt Van Dijck
2019-12-29 19:21 ` [PATCH 3/6] cap11xx: polling mode without irq Kurt Van Dijck
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Kurt Van Dijck @ 2019-12-29 19:21 UTC (permalink / raw)
To: linux-input; +Cc: linux-can, Kurt Van Dijck
Signed-off-by: Kurt Van Dijck <dev.kurt@vandijck-laurijssen.be>
---
drivers/input/keyboard/cap11xx.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 16287ab..092dcd2 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -97,12 +97,14 @@ enum {
CAP1106,
CAP1126,
CAP1188,
+ CAP1208,
};
static const struct cap11xx_hw_model cap11xx_devices[] = {
[CAP1106] = { .product_id = 0x55, .num_channels = 6, .num_leds = 0 },
[CAP1126] = { .product_id = 0x53, .num_channels = 6, .num_leds = 2 },
[CAP1188] = { .product_id = 0x50, .num_channels = 8, .num_leds = 8 },
+ [CAP1208] = { .product_id = 0x6b, .num_channels = 8, .num_leds = 0 },
};
static const struct reg_default cap11xx_reg_defaults[] = {
@@ -472,6 +474,7 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
{ .compatible = "microchip,cap1106", },
{ .compatible = "microchip,cap1126", },
{ .compatible = "microchip,cap1188", },
+ { .compatible = "microchip,cap1208", },
{}
};
MODULE_DEVICE_TABLE(of, cap11xx_dt_ids);
@@ -480,6 +483,7 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
{ "cap1106", CAP1106 },
{ "cap1126", CAP1126 },
{ "cap1188", CAP1188 },
+ { "cap1208", CAP1208 },
{}
};
MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids);
--
1.8.5.rc3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/6] cap11xx: polling mode without irq
2019-12-29 19:21 [RFC] input: cap11xx: plasma globe proof Kurt Van Dijck
2019-12-29 19:21 ` [PATCH 1/6] cap11xx: set device driver_data Kurt Van Dijck
2019-12-29 19:21 ` [PATCH 2/6] cap11xx: support cap1208 Kurt Van Dijck
@ 2019-12-29 19:21 ` Kurt Van Dijck
2019-12-29 19:21 ` [PATCH 4/6] cap11xx: add register definition for LED_LINK Kurt Van Dijck
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Kurt Van Dijck @ 2019-12-29 19:21 UTC (permalink / raw)
To: linux-input; +Cc: linux-can, Kurt Van Dijck
Signed-off-by: Kurt Van Dijck <dev.kurt@vandijck-laurijssen.be>
---
drivers/input/keyboard/cap11xx.c | 49 ++++++++++++++++++++++++++++++++++++----
1 file changed, 45 insertions(+), 4 deletions(-)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 092dcd2..5a7eaed 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/input.h>
+#include <linux/kthread.h>
#include <linux/leds.h>
#include <linux/of_irq.h>
#include <linux/regmap.h>
@@ -78,6 +79,7 @@ struct cap11xx_led {
struct cap11xx_priv {
struct regmap *regmap;
+ struct task_struct *poll_thread;
struct input_dev *idev;
struct cap11xx_led *leds;
@@ -202,6 +204,24 @@ static irqreturn_t cap11xx_thread_func(int irq_num, void *data)
return IRQ_HANDLED;
}
+static int poll_irq(void *data) {
+
+ struct cap11xx_priv *priv = data;
+ int ret;
+ unsigned int status;
+
+ /* until module unload */
+ while (!kthread_should_stop()) {
+ ret = regmap_read(priv->regmap, CAP11XX_REG_MAIN_CONTROL, &status);
+ if (ret >= 0 && (status & 1))
+ cap11xx_thread_func(-1, priv);
+ usleep_range(15000, 25000);
+ }
+
+ return 0;
+}
+
+
static int cap11xx_set_sleep(struct cap11xx_priv *priv, bool sleep)
{
/*
@@ -320,6 +340,17 @@ static int cap11xx_init_leds(struct device *dev,
}
#endif
+static int cap11xx_i2c_remove(struct i2c_client *i2c_client)
+{
+ struct cap11xx_priv *priv = i2c_get_clientdata(i2c_client);
+
+ if (priv->poll_thread) {
+ kthread_stop(priv->poll_thread);
+ mdelay(10);
+ }
+ return 0;
+}
+
static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
@@ -348,8 +379,6 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
if (!priv)
return -ENOMEM;
- i2c_set_clientdata(i2c_client, priv);
-
priv->regmap = devm_regmap_init_i2c(i2c_client, &cap11xx_regmap_config);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
@@ -458,8 +487,19 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
irq = irq_of_parse_and_map(node, 0);
if (!irq) {
- dev_err(dev, "Unable to parse or map IRQ\n");
- return -ENXIO;
+ if (!of_property_read_bool(node, "linux,irq-poll")) {
+ dev_err(dev, "Unable to parse or map IRQ\n");
+ return -ENXIO;
+ }
+ dev_info(dev, "IRQ failed or undefined, using poll_thread\n");
+ priv->poll_thread = kthread_create(poll_irq, priv, "%s-%s-poll",
+ id->name, dev_name(dev));
+ if (!priv->poll_thread) {
+ dev_err(dev, "Unable to start poll_thread\n");
+ return -ENXIO;
+ }
+ wake_up_process(priv->poll_thread);
+ return 0;
}
error = devm_request_threaded_irq(dev, irq, NULL, cap11xx_thread_func,
@@ -495,6 +535,7 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
},
.id_table = cap11xx_i2c_ids,
.probe = cap11xx_i2c_probe,
+ .remove = cap11xx_i2c_remove,
};
module_i2c_driver(cap11xx_i2c_driver);
--
1.8.5.rc3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 5/6] cap11xx: enable all 8 inputs
2019-12-29 19:21 [RFC] input: cap11xx: plasma globe proof Kurt Van Dijck
` (3 preceding siblings ...)
2019-12-29 19:21 ` [PATCH 4/6] cap11xx: add register definition for LED_LINK Kurt Van Dijck
@ 2019-12-29 19:21 ` Kurt Van Dijck
2019-12-29 19:21 ` [PATCH 6/6] cap11xx: export major chip settings to sysfs Kurt Van Dijck
2020-01-09 20:03 ` [RFC] input: cap11xx: plasma globe proof Kurt Van Dijck
6 siblings, 0 replies; 8+ messages in thread
From: Kurt Van Dijck @ 2019-12-29 19:21 UTC (permalink / raw)
To: linux-input; +Cc: linux-can, Kurt Van Dijck
Signed-off-by: Kurt Van Dijck <dev.kurt@vandijck-laurijssen.be>
---
drivers/input/keyboard/cap11xx.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index b666e9e..cdcc89b9 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -117,13 +117,13 @@ enum {
{ CAP11XX_REG_NOISE_FLAG_STATUS, 0x00 },
{ CAP11XX_REG_SENSITIVITY_CONTROL, 0x2f },
{ CAP11XX_REG_CONFIG, 0x20 },
- { CAP11XX_REG_SENSOR_ENABLE, 0x3f },
+ { CAP11XX_REG_SENSOR_ENABLE, 0xff },
{ CAP11XX_REG_SENSOR_CONFIG, 0xa4 },
{ CAP11XX_REG_SENSOR_CONFIG2, 0x07 },
{ CAP11XX_REG_SAMPLING_CONFIG, 0x39 },
{ CAP11XX_REG_CALIBRATION, 0x00 },
- { CAP11XX_REG_INT_ENABLE, 0x3f },
- { CAP11XX_REG_REPEAT_RATE, 0x3f },
+ { CAP11XX_REG_INT_ENABLE, 0xff },
+ { CAP11XX_REG_REPEAT_RATE, 0xff },
{ CAP11XX_REG_MT_CONFIG, 0x80 },
{ CAP11XX_REG_MT_PATTERN_CONFIG, 0x00 },
{ CAP11XX_REG_MT_PATTERN, 0x3f },
@@ -134,6 +134,8 @@ enum {
{ CAP11XX_REG_SENSOR_THRESH(3), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(4), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(5), 0x40 },
+ { CAP11XX_REG_SENSOR_THRESH(6), 0x40 },
+ { CAP11XX_REG_SENSOR_THRESH(7), 0x40 },
{ CAP11XX_REG_SENSOR_NOISE_THRESH, 0x01 },
{ CAP11XX_REG_STANDBY_CHANNEL, 0x00 },
{ CAP11XX_REG_STANDBY_CONFIG, 0x39 },
@@ -157,6 +159,8 @@ static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg)
case CAP11XX_REG_SENOR_DELTA(3):
case CAP11XX_REG_SENOR_DELTA(4):
case CAP11XX_REG_SENOR_DELTA(5):
+ case CAP11XX_REG_SENOR_DELTA(6):
+ case CAP11XX_REG_SENOR_DELTA(7):
case CAP11XX_REG_PRODUCT_ID:
case CAP11XX_REG_MANUFACTURER_ID:
case CAP11XX_REG_REVISION:
--
1.8.5.rc3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6/6] cap11xx: export major chip settings to sysfs
2019-12-29 19:21 [RFC] input: cap11xx: plasma globe proof Kurt Van Dijck
` (4 preceding siblings ...)
2019-12-29 19:21 ` [PATCH 5/6] cap11xx: enable all 8 inputs Kurt Van Dijck
@ 2019-12-29 19:21 ` Kurt Van Dijck
2020-01-09 20:03 ` [RFC] input: cap11xx: plasma globe proof Kurt Van Dijck
6 siblings, 0 replies; 8+ messages in thread
From: Kurt Van Dijck @ 2019-12-29 19:21 UTC (permalink / raw)
To: linux-input; +Cc: linux-can, Kurt Van Dijck
Signed-off-by: Kurt Van Dijck <dev.kurt@vandijck-laurijssen.be>
---
drivers/input/keyboard/cap11xx.c | 161 +++++++++++++++++++++++++++++++++++++++
1 file changed, 161 insertions(+)
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, ®_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")) {
--
1.8.5.rc3
^ permalink raw reply related [flat|nested] 8+ messages in thread