summaryrefslogtreecommitdiff
path: root/drivers/counter
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/counter')
-rw-r--r--drivers/counter/104-quad-8.c36
-rw-r--r--drivers/counter/Kconfig15
-rw-r--r--drivers/counter/Makefile1
-rw-r--r--drivers/counter/counter-chrdev.c137
-rw-r--r--drivers/counter/counter-core.c14
-rw-r--r--drivers/counter/counter-sysfs.c304
-rw-r--r--drivers/counter/ftm-quaddec.c1
-rw-r--r--drivers/counter/intel-qep.c1
-rw-r--r--drivers/counter/interrupt-cnt.c12
-rw-r--r--drivers/counter/microchip-tcb-capture.c1
-rw-r--r--drivers/counter/stm32-lptimer-cnt.c1
-rw-r--r--drivers/counter/stm32-timer-cnt.c1
-rw-r--r--drivers/counter/ti-ecap-capture.c614
-rw-r--r--drivers/counter/ti-eqep.c1
14 files changed, 1064 insertions, 75 deletions
diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
index 4407203e0c9b..1188673d8521 100644
--- a/drivers/counter/104-quad-8.c
+++ b/drivers/counter/104-quad-8.c
@@ -549,6 +549,32 @@ static int quad8_index_polarity_set(struct counter_device *counter,
return 0;
}
+static int quad8_polarity_read(struct counter_device *counter,
+ struct counter_signal *signal,
+ enum counter_signal_polarity *polarity)
+{
+ int err;
+ u32 index_polarity;
+
+ err = quad8_index_polarity_get(counter, signal, &index_polarity);
+ if (err)
+ return err;
+
+ *polarity = (index_polarity) ? COUNTER_SIGNAL_POLARITY_POSITIVE :
+ COUNTER_SIGNAL_POLARITY_NEGATIVE;
+
+ return 0;
+}
+
+static int quad8_polarity_write(struct counter_device *counter,
+ struct counter_signal *signal,
+ enum counter_signal_polarity polarity)
+{
+ const u32 pol = (polarity == COUNTER_SIGNAL_POLARITY_POSITIVE) ? 1 : 0;
+
+ return quad8_index_polarity_set(counter, signal, pol);
+}
+
static const char *const quad8_synchronous_modes[] = {
"non-synchronous",
"synchronous"
@@ -977,6 +1003,13 @@ static struct counter_comp quad8_signal_ext[] = {
quad8_signal_fck_prescaler_write)
};
+static const enum counter_signal_polarity quad8_polarities[] = {
+ COUNTER_SIGNAL_POLARITY_POSITIVE,
+ COUNTER_SIGNAL_POLARITY_NEGATIVE,
+};
+
+static DEFINE_COUNTER_AVAILABLE(quad8_polarity_available, quad8_polarities);
+
static DEFINE_COUNTER_ENUM(quad8_index_pol_enum, quad8_index_polarity_modes);
static DEFINE_COUNTER_ENUM(quad8_synch_mode_enum, quad8_synchronous_modes);
@@ -984,6 +1017,8 @@ static struct counter_comp quad8_index_ext[] = {
COUNTER_COMP_SIGNAL_ENUM("index_polarity", quad8_index_polarity_get,
quad8_index_polarity_set,
quad8_index_pol_enum),
+ COUNTER_COMP_POLARITY(quad8_polarity_read, quad8_polarity_write,
+ quad8_polarity_available),
COUNTER_COMP_SIGNAL_ENUM("synchronous_mode", quad8_synchronous_mode_get,
quad8_synchronous_mode_set,
quad8_synch_mode_enum),
@@ -1241,3 +1276,4 @@ module_isa_driver(quad8_driver, num_quad8);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(COUNTER);
diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
index 5edd155f1911..d388bf26f4dc 100644
--- a/drivers/counter/Kconfig
+++ b/drivers/counter/Kconfig
@@ -101,4 +101,19 @@ config INTEL_QEP
To compile this driver as a module, choose M here: the module
will be called intel-qep.
+config TI_ECAP_CAPTURE
+ tristate "TI eCAP capture driver"
+ depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
+ depends on HAS_IOMEM
+ select REGMAP_MMIO
+ help
+ Select this option to enable the Texas Instruments Enhanced Capture
+ (eCAP) driver in input mode.
+
+ It can be used to timestamp events (falling/rising edges) detected
+ on ECAP input signal.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ti-ecap-capture.
+
endif # COUNTER
diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
index 8fde6c100ebc..b9a369e0d4fc 100644
--- a/drivers/counter/Makefile
+++ b/drivers/counter/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_TI_EQEP) += ti-eqep.o
obj-$(CONFIG_FTM_QUADDEC) += ftm-quaddec.o
obj-$(CONFIG_MICROCHIP_TCB_CAPTURE) += microchip-tcb-capture.o
obj-$(CONFIG_INTEL_QEP) += intel-qep.o
+obj-$(CONFIG_TI_ECAP_CAPTURE) += ti-ecap-capture.o
diff --git a/drivers/counter/counter-chrdev.c b/drivers/counter/counter-chrdev.c
index 69d340be9c93..80acdf62794a 100644
--- a/drivers/counter/counter-chrdev.c
+++ b/drivers/counter/counter-chrdev.c
@@ -40,7 +40,11 @@ struct counter_comp_node {
a.signal_u32_read == b.signal_u32_read || \
a.device_u64_read == b.device_u64_read || \
a.count_u64_read == b.count_u64_read || \
- a.signal_u64_read == b.signal_u64_read)
+ a.signal_u64_read == b.signal_u64_read || \
+ a.signal_array_u32_read == b.signal_array_u32_read || \
+ a.device_array_u64_read == b.device_array_u64_read || \
+ a.count_array_u64_read == b.count_array_u64_read || \
+ a.signal_array_u64_read == b.signal_array_u64_read)
#define counter_comp_read_is_set(comp) \
(comp.action_read || \
@@ -52,7 +56,11 @@ struct counter_comp_node {
comp.signal_u32_read || \
comp.device_u64_read || \
comp.count_u64_read || \
- comp.signal_u64_read)
+ comp.signal_u64_read || \
+ comp.signal_array_u32_read || \
+ comp.device_array_u64_read || \
+ comp.count_array_u64_read || \
+ comp.signal_array_u64_read)
static ssize_t counter_chrdev_read(struct file *filp, char __user *buf,
size_t len, loff_t *f_ps)
@@ -228,6 +236,31 @@ static int counter_disable_events(struct counter_device *const counter)
return err;
}
+static int counter_get_ext(const struct counter_comp *const ext,
+ const size_t num_ext, const size_t component_id,
+ size_t *const ext_idx, size_t *const id)
+{
+ struct counter_array *element;
+
+ *id = 0;
+ for (*ext_idx = 0; *ext_idx < num_ext; (*ext_idx)++) {
+ if (*id == component_id)
+ return 0;
+
+ if (ext->type == COUNTER_COMP_ARRAY) {
+ element = ext->priv;
+
+ if (component_id - *id < element->length)
+ return 0;
+
+ *id += element->length;
+ } else
+ (*id)++;
+ }
+
+ return -EINVAL;
+}
+
static int counter_add_watch(struct counter_device *const counter,
const unsigned long arg)
{
@@ -237,6 +270,7 @@ static int counter_add_watch(struct counter_device *const counter,
size_t parent, id;
struct counter_comp *ext;
size_t num_ext;
+ size_t ext_idx, ext_id;
int err = 0;
if (copy_from_user(&watch, uwatch, sizeof(watch)))
@@ -314,11 +348,11 @@ static int counter_add_watch(struct counter_device *const counter,
comp_node.comp.priv = counter->counts[parent].synapses + id;
break;
case COUNTER_COMPONENT_EXTENSION:
- if (id >= num_ext)
- return -EINVAL;
- id = array_index_nospec(id, num_ext);
+ err = counter_get_ext(ext, num_ext, id, &ext_idx, &ext_id);
+ if (err < 0)
+ return err;
- comp_node.comp = ext[id];
+ comp_node.comp = ext[ext_idx];
break;
default:
return -EINVAL;
@@ -451,14 +485,56 @@ void counter_chrdev_remove(struct counter_device *const counter)
kfifo_free(&counter->events);
}
+static int counter_get_array_data(struct counter_device *const counter,
+ const enum counter_scope scope,
+ void *const parent,
+ const struct counter_comp *const comp,
+ const size_t idx, u64 *const value)
+{
+ const struct counter_array *const element = comp->priv;
+ u32 value_u32 = 0;
+ int ret;
+
+ switch (element->type) {
+ case COUNTER_COMP_SIGNAL_POLARITY:
+ if (scope != COUNTER_SCOPE_SIGNAL)
+ return -EINVAL;
+ ret = comp->signal_array_u32_read(counter, parent, idx,
+ &value_u32);
+ *value = value_u32;
+ return ret;
+ case COUNTER_COMP_U64:
+ switch (scope) {
+ case COUNTER_SCOPE_DEVICE:
+ return comp->device_array_u64_read(counter, idx, value);
+ case COUNTER_SCOPE_SIGNAL:
+ return comp->signal_array_u64_read(counter, parent, idx,
+ value);
+ case COUNTER_SCOPE_COUNT:
+ return comp->count_array_u64_read(counter, parent, idx,
+ value);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
static int counter_get_data(struct counter_device *const counter,
const struct counter_comp_node *const comp_node,
u64 *const value)
{
const struct counter_comp *const comp = &comp_node->comp;
- void *const parent = comp_node->parent;
+ const enum counter_scope scope = comp_node->component.scope;
+ const size_t id = comp_node->component.id;
+ struct counter_signal *const signal = comp_node->parent;
+ struct counter_count *const count = comp_node->parent;
u8 value_u8 = 0;
u32 value_u32 = 0;
+ const struct counter_comp *ext;
+ size_t num_ext;
+ size_t ext_idx, ext_id;
int ret;
if (comp_node->component.type == COUNTER_COMPONENT_NONE)
@@ -467,15 +543,15 @@ static int counter_get_data(struct counter_device *const counter,
switch (comp->type) {
case COUNTER_COMP_U8:
case COUNTER_COMP_BOOL:
- switch (comp_node->component.scope) {
+ switch (scope) {
case COUNTER_SCOPE_DEVICE:
ret = comp->device_u8_read(counter, &value_u8);
break;
case COUNTER_SCOPE_SIGNAL:
- ret = comp->signal_u8_read(counter, parent, &value_u8);
+ ret = comp->signal_u8_read(counter, signal, &value_u8);
break;
case COUNTER_SCOPE_COUNT:
- ret = comp->count_u8_read(counter, parent, &value_u8);
+ ret = comp->count_u8_read(counter, count, &value_u8);
break;
default:
return -EINVAL;
@@ -487,16 +563,17 @@ static int counter_get_data(struct counter_device *const counter,
case COUNTER_COMP_ENUM:
case COUNTER_COMP_COUNT_DIRECTION:
case COUNTER_COMP_COUNT_MODE:
- switch (comp_node->component.scope) {
+ case COUNTER_COMP_SIGNAL_POLARITY:
+ switch (scope) {
case COUNTER_SCOPE_DEVICE:
ret = comp->device_u32_read(counter, &value_u32);
break;
case COUNTER_SCOPE_SIGNAL:
- ret = comp->signal_u32_read(counter, parent,
+ ret = comp->signal_u32_read(counter, signal,
&value_u32);
break;
case COUNTER_SCOPE_COUNT:
- ret = comp->count_u32_read(counter, parent, &value_u32);
+ ret = comp->count_u32_read(counter, count, &value_u32);
break;
default:
return -EINVAL;
@@ -504,21 +581,43 @@ static int counter_get_data(struct counter_device *const counter,
*value = value_u32;
return ret;
case COUNTER_COMP_U64:
- switch (comp_node->component.scope) {
+ switch (scope) {
case COUNTER_SCOPE_DEVICE:
return comp->device_u64_read(counter, value);
case COUNTER_SCOPE_SIGNAL:
- return comp->signal_u64_read(counter, parent, value);
+ return comp->signal_u64_read(counter, signal, value);
case COUNTER_SCOPE_COUNT:
- return comp->count_u64_read(counter, parent, value);
+ return comp->count_u64_read(counter, count, value);
default:
return -EINVAL;
}
case COUNTER_COMP_SYNAPSE_ACTION:
- ret = comp->action_read(counter, parent, comp->priv,
- &value_u32);
+ ret = comp->action_read(counter, count, comp->priv, &value_u32);
*value = value_u32;
return ret;
+ case COUNTER_COMP_ARRAY:
+ switch (scope) {
+ case COUNTER_SCOPE_DEVICE:
+ ext = counter->ext;
+ num_ext = counter->num_ext;
+ break;
+ case COUNTER_SCOPE_SIGNAL:
+ ext = signal->ext;
+ num_ext = signal->num_ext;
+ break;
+ case COUNTER_SCOPE_COUNT:
+ ext = count->ext;
+ num_ext = count->num_ext;
+ break;
+ default:
+ return -EINVAL;
+ }
+ ret = counter_get_ext(ext, num_ext, id, &ext_idx, &ext_id);
+ if (ret < 0)
+ return ret;
+
+ return counter_get_array_data(counter, scope, comp_node->parent,
+ comp, id - ext_id, value);
default:
return -EINVAL;
}
@@ -574,4 +673,4 @@ exit_early:
if (copied)
wake_up_poll(&counter->events_wait, EPOLLIN);
}
-EXPORT_SYMBOL_GPL(counter_push_event);
+EXPORT_SYMBOL_NS_GPL(counter_push_event, COUNTER);
diff --git a/drivers/counter/counter-core.c b/drivers/counter/counter-core.c
index 938651f9e9e0..09c77afb33ca 100644
--- a/drivers/counter/counter-core.c
+++ b/drivers/counter/counter-core.c
@@ -73,7 +73,7 @@ void *counter_priv(const struct counter_device *const counter)
return &ch->privdata;
}
-EXPORT_SYMBOL_GPL(counter_priv);
+EXPORT_SYMBOL_NS_GPL(counter_priv, COUNTER);
/**
* counter_alloc - allocate a counter_device
@@ -133,13 +133,13 @@ err_ida_alloc:
return NULL;
}
-EXPORT_SYMBOL_GPL(counter_alloc);
+EXPORT_SYMBOL_NS_GPL(counter_alloc, COUNTER);
void counter_put(struct counter_device *counter)
{
put_device(&counter->dev);
}
-EXPORT_SYMBOL_GPL(counter_put);
+EXPORT_SYMBOL_NS_GPL(counter_put, COUNTER);
/**
* counter_add - complete registration of a counter
@@ -166,7 +166,7 @@ int counter_add(struct counter_device *counter)
/* implies device_add(dev) */
return cdev_device_add(&counter->chrdev, dev);
}
-EXPORT_SYMBOL_GPL(counter_add);
+EXPORT_SYMBOL_NS_GPL(counter_add, COUNTER);
/**
* counter_unregister - unregister Counter from the system
@@ -188,7 +188,7 @@ void counter_unregister(struct counter_device *const counter)
mutex_unlock(&counter->ops_exist_lock);
}
-EXPORT_SYMBOL_GPL(counter_unregister);
+EXPORT_SYMBOL_NS_GPL(counter_unregister, COUNTER);
static void devm_counter_release(void *counter)
{
@@ -223,7 +223,7 @@ struct counter_device *devm_counter_alloc(struct device *dev, size_t sizeof_priv
return counter;
}
-EXPORT_SYMBOL_GPL(devm_counter_alloc);
+EXPORT_SYMBOL_NS_GPL(devm_counter_alloc, COUNTER);
/**
* devm_counter_add - complete registration of a counter
@@ -244,7 +244,7 @@ int devm_counter_add(struct device *dev,
return devm_add_action_or_reset(dev, devm_counter_release, counter);
}
-EXPORT_SYMBOL_GPL(devm_counter_add);
+EXPORT_SYMBOL_NS_GPL(devm_counter_add, COUNTER);
#define COUNTER_DEV_MAX 256
diff --git a/drivers/counter/counter-sysfs.c b/drivers/counter/counter-sysfs.c
index 04eac41dad33..b9efe66f9f8d 100644
--- a/drivers/counter/counter-sysfs.c
+++ b/drivers/counter/counter-sysfs.c
@@ -91,6 +91,11 @@ static const char *const counter_count_mode_str[] = {
[COUNTER_COUNT_MODE_MODULO_N] = "modulo-n"
};
+static const char *const counter_signal_polarity_str[] = {
+ [COUNTER_SIGNAL_POLARITY_POSITIVE] = "positive",
+ [COUNTER_SIGNAL_POLARITY_NEGATIVE] = "negative"
+};
+
static ssize_t counter_comp_u8_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -201,6 +206,8 @@ static ssize_t counter_comp_u32_show(struct device *dev,
return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]);
case COUNTER_COMP_COUNT_MODE:
return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]);
+ case COUNTER_COMP_SIGNAL_POLARITY:
+ return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
default:
return sysfs_emit(buf, "%u\n", (unsigned int)data);
}
@@ -252,6 +259,10 @@ static ssize_t counter_comp_u32_store(struct device *dev,
err = counter_find_enum(&data, avail->enums, avail->num_items,
buf, counter_count_mode_str);
break;
+ case COUNTER_COMP_SIGNAL_POLARITY:
+ err = counter_find_enum(&data, avail->enums, avail->num_items,
+ buf, counter_signal_polarity_str);
+ break;
default:
err = kstrtou32(buf, 0, &data);
break;
@@ -341,6 +352,124 @@ static ssize_t counter_comp_u64_store(struct device *dev,
return len;
}
+static ssize_t counter_comp_array_u32_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ const struct counter_attribute *const a = to_counter_attribute(attr);
+ struct counter_device *const counter = counter_from_dev(dev);
+ const struct counter_array *const element = a->comp.priv;
+ int err;
+ u32 data = 0;
+
+ if (a->scope != COUNTER_SCOPE_SIGNAL ||
+ element->type != COUNTER_COMP_SIGNAL_POLARITY)
+ return -EINVAL;
+
+ err = a->comp.signal_array_u32_read(counter, a->parent, element->idx,
+ &data);
+ if (err < 0)
+ return err;
+
+ return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
+}
+
+static ssize_t counter_comp_array_u32_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ const struct counter_attribute *const a = to_counter_attribute(attr);
+ struct counter_device *const counter = counter_from_dev(dev);
+ const struct counter_array *const element = a->comp.priv;
+ int err;
+ u32 data = 0;
+
+ if (element->type != COUNTER_COMP_SIGNAL_POLARITY ||
+ a->scope != COUNTER_SCOPE_SIGNAL)
+ return -EINVAL;
+
+ err = counter_find_enum(&data, element->avail->enums,
+ element->avail->num_items, buf,
+ counter_signal_polarity_str);
+ if (err < 0)
+ return err;
+
+ err = a->comp.signal_array_u32_write(counter, a->parent, element->idx,
+ data);
+ if (err < 0)
+ return err;
+
+ return len;
+}
+
+static ssize_t counter_comp_array_u64_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ const struct counter_attribute *const a = to_counter_attribute(attr);
+ struct counter_device *const counter = counter_from_dev(dev);
+ const struct counter_array *const element = a->comp.priv;
+ int err;
+ u64 data = 0;
+
+ switch (a->scope) {
+ case COUNTER_SCOPE_DEVICE:
+ err = a->comp.device_array_u64_read(counter, element->idx,
+ &data);
+ break;
+ case COUNTER_SCOPE_SIGNAL:
+ err = a->comp.signal_array_u64_read(counter, a->parent,
+ element->idx, &data);
+ break;
+ case COUNTER_SCOPE_COUNT:
+ err = a->comp.count_array_u64_read(counter, a->parent,
+ element->idx, &data);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (err < 0)
+ return err;
+
+ return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
+}
+
+static ssize_t counter_comp_array_u64_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ const struct counter_attribute *const a = to_counter_attribute(attr);
+ struct counter_device *const counter = counter_from_dev(dev);
+ const struct counter_array *const element = a->comp.priv;
+ int err;
+ u64 data = 0;
+
+ err = kstrtou64(buf, 0, &data);
+ if (err < 0)
+ return err;
+
+ switch (a->scope) {
+ case COUNTER_SCOPE_DEVICE:
+ err = a->comp.device_array_u64_write(counter, element->idx,
+ data);
+ break;
+ case COUNTER_SCOPE_SIGNAL:
+ err = a->comp.signal_array_u64_write(counter, a->parent,
+ element->idx, data);
+ break;
+ case COUNTER_SCOPE_COUNT:
+ err = a->comp.count_array_u64_write(counter, a->parent,
+ element->idx, data);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (err < 0)
+ return err;
+
+ return len;
+}
+
static ssize_t enums_available_show(const u32 *const enums,
const size_t num_enums,
const char *const strs[], char *buf)
@@ -435,6 +564,7 @@ static int counter_attr_create(struct device *const dev,
const enum counter_scope scope,
void *const parent)
{
+ const struct counter_array *const array = comp->priv;
struct counter_attribute *counter_attr;
struct device_attribute *dev_attr;
@@ -469,6 +599,7 @@ static int counter_attr_create(struct device *const dev,
case COUNTER_COMP_ENUM:
case COUNTER_COMP_COUNT_DIRECTION:
case COUNTER_COMP_COUNT_MODE:
+ case COUNTER_COMP_SIGNAL_POLARITY:
if (comp->device_u32_read) {
dev_attr->attr.mode |= 0444;
dev_attr->show = counter_comp_u32_show;
@@ -488,6 +619,32 @@ static int counter_attr_create(struct device *const dev,
dev_attr->store = counter_comp_u64_store;
}
break;
+ case COUNTER_COMP_ARRAY:
+ switch (array->type) {
+ case COUNTER_COMP_SIGNAL_POLARITY:
+ if (comp->signal_array_u32_read) {
+ dev_attr->attr.mode |= 0444;
+ dev_attr->show = counter_comp_array_u32_show;
+ }
+ if (comp->signal_array_u32_write) {
+ dev_attr->attr.mode |= 0200;
+ dev_attr->store = counter_comp_array_u32_store;
+ }
+ break;
+ case COUNTER_COMP_U64:
+ if (comp->device_array_u64_read) {
+ dev_attr->attr.mode |= 0444;
+ dev_attr->show = counter_comp_array_u64_show;
+ }
+ if (comp->device_array_u64_write) {
+ dev_attr->attr.mode |= 0200;
+ dev_attr->store = counter_comp_array_u64_store;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
default:
return -EINVAL;
}
@@ -580,6 +737,95 @@ static int counter_comp_id_attr_create(struct device *const dev,
return 0;
}
+static int counter_ext_attrs_create(struct device *const dev,
+ struct counter_attribute_group *const group,
+ const struct counter_comp *const ext,
+ const enum counter_scope scope,
+ void *const parent, const size_t id)
+{
+ int err;
+
+ /* Create main extension attribute */
+ err = counter_attr_create(dev, group, ext, scope, parent);
+ if (err < 0)
+ return err;
+
+ /* Create extension id attribute */
+ return counter_comp_id_attr_create(dev, group, ext->name, id);
+}
+
+static int counter_array_attrs_create(struct device *const dev,
+ struct counter_attribute_group *const group,
+ const struct counter_comp *const comp,
+ const enum counter_scope scope,
+ void *const parent, const size_t id)
+{
+ const struct counter_array *const array = comp->priv;
+ struct counter_comp ext = *comp;
+ struct counter_array *element;
+ size_t idx;
+ int err;
+
+ /* Create an attribute for each array element */
+ for (idx = 0; idx < array->length; idx++) {
+ /* Generate array element attribute name */
+ ext.name = devm_kasprintf(dev, GFP_KERNEL, "%s%zu", comp->name,
+ idx);
+ if (!ext.name)
+ return -ENOMEM;
+
+ /* Allocate and configure array element */
+ element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL);
+ if (!element)
+ return -ENOMEM;
+ element->type = array->type;
+ element->avail = array->avail;
+ element->idx = idx;
+ ext.priv = element;
+
+ /* Create all attributes associated with the array element */
+ err = counter_ext_attrs_create(dev, group, &ext, scope, parent,
+ id + idx);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int counter_sysfs_exts_add(struct device *const dev,
+ struct counter_attribute_group *const group,
+ const struct counter_comp *const exts,
+ const size_t num_ext,
+ const enum counter_scope scope,
+ void *const parent)
+{
+ size_t i;
+ const struct counter_comp *ext;
+ int err;
+ size_t id = 0;
+ const struct counter_array *array;
+
+ /* Create attributes for each extension */
+ for (i = 0; i < num_ext; i++) {
+ ext = &exts[i];
+ if (ext->type == COUNTER_COMP_ARRAY) {
+ err = counter_array_attrs_create(dev, group, ext, scope,
+ parent, id);
+ array = ext->priv;
+ id += array->length;
+ } else {
+ err = counter_ext_attrs_create(dev, group, ext, scope,
+ parent, id);
+ id++;
+ }
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
static struct counter_comp counter_signal_comp = {
.type = COUNTER_COMP_SIGNAL_LEVEL,
.name = "signal",
@@ -593,8 +839,6 @@ static int counter_signal_attrs_create(struct counter_device *const counter,
struct device *const dev = &counter->dev;
int err;
struct counter_comp comp;
- size_t i;
- struct counter_comp *ext;
/* Create main Signal attribute */
comp = counter_signal_comp;
@@ -608,21 +852,9 @@ static int counter_signal_attrs_create(struct counter_device *const counter,
if (err < 0)
return err;
- /* Create an attribute for each extension */
- for (i = 0; i < signal->num_ext; i++) {
- ext = &signal->ext[i];
-
- err = counter_attr_create(dev, cattr_group, ext, scope, signal);
- if (err < 0)
- return err;
-
- err = counter_comp_id_attr_create(dev, cattr_group, ext->name,
- i);
- if (err < 0)
- return err;
- }
-
- return 0;
+ /* Add Signal extensions */
+ return counter_sysfs_exts_add(dev, cattr_group, signal->ext,
+ signal->num_ext, scope, signal);
}
static int counter_sysfs_signals_add(struct counter_device *const counter,
@@ -707,8 +939,6 @@ static int counter_count_attrs_create(struct counter_device *const counter,
struct device *const dev = &counter->dev;
int err;
struct counter_comp comp;
- size_t i;
- struct counter_comp *ext;
/* Create main Count attribute */
comp = counter_count_comp;
@@ -731,21 +961,9 @@ static int counter_count_attrs_create(struct counter_device *const counter,
if (err < 0)
return err;
- /* Create an attribute for each extension */
- for (i = 0; i < count->num_ext; i++) {
- ext = &count->ext[i];
-
- err = counter_attr_create(dev, cattr_group, ext, scope, count);
- if (err < 0)
- return err;
-
- err = counter_comp_id_attr_create(dev, cattr_group, ext->name,
- i);
- if (err < 0)
- return err;
- }
-
- return 0;
+ /* Add Count extensions */
+ return counter_sysfs_exts_add(dev, cattr_group, count->ext,
+ count->num_ext, scope, count);
}
static int counter_sysfs_counts_add(struct counter_device *const counter,
@@ -838,8 +1056,6 @@ static int counter_sysfs_attr_add(struct counter_device *const counter,
const enum counter_scope scope = COUNTER_SCOPE_DEVICE;
struct device *const dev = &counter->dev;
int err;
- size_t i;
- struct counter_comp *ext;
/* Add Signals sysfs attributes */
err = counter_sysfs_signals_add(counter, cattr_group);
@@ -876,19 +1092,9 @@ static int counter_sysfs_attr_add(struct counter_device *const counter,
if (err < 0)
return err;
- /* Create an attribute for each extension */
- for (i = 0; i < counter->num_ext; i++) {
- ext = &counter->ext[i];
-
- err = counter_attr_create(dev, cattr_group, ext, scope, NULL);
- if (err < 0)
- return err;
-
- err = counter_comp_id_attr_create(dev, cattr_group, ext->name,
- i);
- if (err < 0)
- return err;
- }
+ /* Add device extensions */
+ return counter_sysfs_exts_add(dev, cattr_group, counter->ext,
+ counter->num_ext, scope, NULL);
return 0;
}
diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c
index 2a58582a9df4..aea6622a9b13 100644
--- a/drivers/counter/ftm-quaddec.c
+++ b/drivers/counter/ftm-quaddec.c
@@ -325,3 +325,4 @@ module_platform_driver(ftm_quaddec_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kjeld Flarup <kfa@deif.com>");
MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com>");
+MODULE_IMPORT_NS(COUNTER);
diff --git a/drivers/counter/intel-qep.c b/drivers/counter/intel-qep.c
index 47a6a9dfc9e8..af5942e66f7d 100644
--- a/drivers/counter/intel-qep.c
+++ b/drivers/counter/intel-qep.c
@@ -523,3 +523,4 @@ MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Intel Quadrature Encoder Peripheral driver");
+MODULE_IMPORT_NS(COUNTER);
diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c
index 3b13f56bbb11..229473855c5b 100644
--- a/drivers/counter/interrupt-cnt.c
+++ b/drivers/counter/interrupt-cnt.c
@@ -139,12 +139,23 @@ static int interrupt_cnt_signal_read(struct counter_device *counter,
return 0;
}
+static int interrupt_cnt_watch_validate(struct counter_device *counter,
+ const struct counter_watch *watch)
+{
+ if (watch->channel != 0 ||
+ watch->event != COUNTER_EVENT_CHANGE_OF_STATE)
+ return -EINVAL;
+
+ return 0;
+}
+
static const struct counter_ops interrupt_cnt_ops = {
.action_read = interrupt_cnt_action_read,
.count_read = interrupt_cnt_read,
.count_write = interrupt_cnt_write,
.function_read = interrupt_cnt_function_read,
.signal_read = interrupt_cnt_signal_read,
+ .watch_validate = interrupt_cnt_watch_validate,
};
static int interrupt_cnt_probe(struct platform_device *pdev)
@@ -242,3 +253,4 @@ MODULE_ALIAS("platform:interrupt-counter");
MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
MODULE_DESCRIPTION("Interrupt counter driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(COUNTER);
diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c
index 00844445143b..f9dee15d9777 100644
--- a/drivers/counter/microchip-tcb-capture.c
+++ b/drivers/counter/microchip-tcb-capture.c
@@ -394,3 +394,4 @@ module_platform_driver(mchp_tc_driver);
MODULE_AUTHOR("Kamel Bouhara <kamel.bouhara@bootlin.com>");
MODULE_DESCRIPTION("Microchip TCB Capture driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(COUNTER);
diff --git a/drivers/counter/stm32-lptimer-cnt.c b/drivers/counter/stm32-lptimer-cnt.c
index 68031d93ce89..d6b80b6dfc28 100644
--- a/drivers/counter/stm32-lptimer-cnt.c
+++ b/drivers/counter/stm32-lptimer-cnt.c
@@ -520,3 +520,4 @@ MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
MODULE_ALIAS("platform:stm32-lptimer-counter");
MODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM counter driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(COUNTER);
diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c
index 5779ae7c73cf..9bf20a5d6bda 100644
--- a/drivers/counter/stm32-timer-cnt.c
+++ b/drivers/counter/stm32-timer-cnt.c
@@ -417,3 +417,4 @@ MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_ALIAS("platform:stm32-timer-counter");
MODULE_DESCRIPTION("STMicroelectronics STM32 TIMER counter driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(COUNTER);
diff --git a/drivers/counter/ti-ecap-capture.c b/drivers/counter/ti-ecap-capture.c
new file mode 100644
index 000000000000..af10de30aba5
--- /dev/null
+++ b/drivers/counter/ti-ecap-capture.c
@@ -0,0 +1,614 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ECAP Capture driver
+ *
+ * Copyright (C) 2022 Julien Panis <jpanis@baylibre.com>
+ */
+
+#include <linux/atomic.h>