diff --git a/MAINTAINERS b/MAINTAINERS
index ef72b5755793..150ad8a9bb87 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4365,6 +4365,7 @@ F:	Documentation/ABI/testing/sysfs-bus-counter*
 F:	Documentation/driver-api/generic-counter.rst
 F:	drivers/counter/
 F:	include/linux/counter.h
+F:	include/uapi/linux/counter.h
 F:	include/uapi/linux/counter-types.h
 
 CPMAC ETHERNET DRIVER
diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
index f48e337cbd85..d219b9c058e7 100644
--- a/drivers/counter/Makefile
+++ b/drivers/counter/Makefile
@@ -4,7 +4,7 @@
 #
 
 obj-$(CONFIG_COUNTER) += counter.o
-counter-y := counter-core.o counter-sysfs.o
+counter-y := counter-core.o counter-sysfs.o counter-chrdev.o
 
 obj-$(CONFIG_104_QUAD_8)	+= 104-quad-8.o
 obj-$(CONFIG_STM32_TIMER_CNT)	+= stm32-timer-cnt.o
diff --git a/drivers/counter/counter-chrdev.c b/drivers/counter/counter-chrdev.c
new file mode 100644
index 000000000000..7fd55bf71e47
--- /dev/null
+++ b/drivers/counter/counter-chrdev.c
@@ -0,0 +1,656 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generic Counter character device interface
+ * Copyright (C) 2020 William Breathitt Gray
+ */
+
+#include <linux/cdev.h>
+#include <linux/counter.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/kdev_t.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+enum counter_owner_type {
+	COUNTER_OWNER_TYPE_DEVICE,
+	COUNTER_OWNER_TYPE_SIGNAL,
+	COUNTER_OWNER_TYPE_COUNT,
+};
+
+struct counter_control {
+	loff_t offset;
+	size_t size;
+	struct list_head l;
+
+	struct counter_data data;
+	enum counter_owner_type type;
+	void *owner;
+};
+
+static int counter_data_u8_read(struct counter_device *const counter,
+				const struct counter_control *const control,
+				u8 __user *const buf)
+{
+	const struct counter_data *const data = &control->data;
+	int err;
+	u8 val;
+
+	switch (control->type) {
+	case COUNTER_OWNER_TYPE_DEVICE:
+		err = data->device_u8_read(counter, &val);
+		break;
+	case COUNTER_OWNER_TYPE_SIGNAL:
+		err = data->signal_u8_read(counter, control->owner, &val);
+		break;
+	case COUNTER_OWNER_TYPE_COUNT:
+		if (data->type == COUNTER_DATA_TYPE_SYNAPSE_ACTION)
+			err = data->action_read(counter, control->owner,
+						data->priv, &val);
+		else
+			err = data->count_u8_read(counter, control->owner,
+						  &val);
+		break;
+	default: return -EINVAL;
+	}
+	if (err)
+		return err;
+
+	return put_user(val, buf);
+}
+
+static int counter_data_u64_read(struct counter_device *const counter,
+				 const struct counter_control *const control,
+				 char __user *const buf, const size_t len,
+				 const size_t offset)
+{
+	const struct counter_data *const data = &control->data;
+	int err;
+	u64 val;
+
+	switch (control->type) {
+	case COUNTER_OWNER_TYPE_DEVICE:
+		err = data->device_u64_read(counter, &val);
+		break;
+	case COUNTER_OWNER_TYPE_SIGNAL:
+		err = data->signal_u64_read(counter, control->owner, &val);
+		break;
+	case COUNTER_OWNER_TYPE_COUNT:
+		err = data->count_u64_read(counter, control->owner, &val);
+		break;
+	default: return -EINVAL;
+	}
+	if (err)
+		return err;
+
+	return copy_to_user(buf, (const char *)&val + offset, len);
+}
+
+static int counter_data_string_read(struct counter_device *const counter,
+				    const struct counter_control *const control,
+				    char __user *const buf, const size_t len,
+				    const size_t offset)
+{
+	const struct counter_data *const data = &control->data;
+	int err;
+	char str[64] = "";
+
+	switch (control->type) {
+	case COUNTER_OWNER_TYPE_DEVICE:
+		err = data->device_string_read(counter, str, sizeof(str));
+		break;
+	case COUNTER_OWNER_TYPE_SIGNAL:
+		err = data->signal_string_read(counter, control->owner, str,
+					       sizeof(str));
+		break;
+	case COUNTER_OWNER_TYPE_COUNT:
+		err = data->count_string_read(counter, control->owner, str,
+					      sizeof(str));
+		break;
+	default: return -EINVAL;
+	}
+	if (err < 0)
+		return err;
+
+	return copy_to_user(buf, str + offset, len);
+}
+
+static int counter_control_read(struct counter_device *const counter,
+				const struct counter_control *const control,
+				char __user *const buf, const size_t len,
+				const size_t offset)
+{
+	/* Check if read operation is supported */
+	if (!control->data.device_u8_read)
+		return -EFAULT;
+
+	switch (control->data.type) {
+	case COUNTER_DATA_TYPE_U8:
+	case COUNTER_DATA_TYPE_BOOL:
+	case COUNTER_DATA_TYPE_SIGNAL:
+	case COUNTER_DATA_TYPE_COUNT_FUNCTION:
+	case COUNTER_DATA_TYPE_SYNAPSE_ACTION:
+	case COUNTER_DATA_TYPE_COUNT_DIRECTION:
+	case COUNTER_DATA_TYPE_COUNT_MODE:
+		return counter_data_u8_read(counter, control, buf);
+	case COUNTER_DATA_TYPE_U64:
+		return counter_data_u64_read(counter, control, buf, len,
+					     offset);
+	case COUNTER_DATA_TYPE_STRING:
+		return counter_data_string_read(counter, control, buf, len,
+						offset);
+	}
+
+	return -EINVAL;
+}
+
+static ssize_t counter_chrdev_read(struct file *filp, char __user *buf,
+				   size_t len, loff_t *f_ps)
+{
+	const loff_t start_ps = *f_ps;
+	struct counter_device *const counter = filp->private_data;
+	size_t read_size;
+	struct counter_control *control;
+	int err;
+	loff_t next_control_ps;
+
+	/* Handle Counter control selection */
+	if (*f_ps < COUNTER_SELECTION_SIZE) {
+		read_size = (*f_ps + len > COUNTER_SELECTION_SIZE) ?
+			    COUNTER_SELECTION_SIZE - *f_ps : len;
+
+		if (copy_to_user(buf, counter->selection + *f_ps, read_size))
+			return -EFAULT;
+
+		*f_ps += read_size;
+		buf += read_size;
+		len -= read_size;
+		if (!len)
+			goto exit_chrdev_read;
+	}
+
+	/* Handle controls */
+	list_for_each_entry(control, &counter->control_list, l) {
+		next_control_ps = control->offset + control->size;
+
+		/* Find first control item */
+		if (*f_ps >= next_control_ps)
+			continue;
+
+		read_size = (*f_ps + len > next_control_ps) ?
+			    next_control_ps - *f_ps : len;
+
+		err = counter_control_read(counter, control, buf, read_size,
+					   control->offset - *f_ps);
+		if (err)
+			return err;
+
+		*f_ps += read_size;
+		buf += read_size;
+		len -= read_size;
+		if (!len)
+			goto exit_chrdev_read;
+	}
+
+exit_chrdev_read:
+	return *f_ps - start_ps;
+}
+
+static int counter_control_ext_add(const u8 *const selection,
+				   const enum counter_owner_type type,
+				   void *const owner, const size_t num_ext,
+				   const struct counter_data *const ext,
+				   struct list_head *const cntrl_list,
+				   loff_t *const offset)
+{
+	struct counter_control *p = list_last_entry(cntrl_list, typeof(*p), l);
+	struct counter_control *n;
+	size_t i;
+	struct counter_control *control;
+	int err;
+
+	for (i = 0; i < num_ext; i++) {
+		/* Check if extension is selected */
+		if (!selection[i])
+			continue;
+
+		/* Generate control list item */
+		control = kzalloc(sizeof(*control), GFP_KERNEL);
+		if (!control) {
+			err = -ENOMEM;
+			goto err_control_ext_create;
+		}
+		list_add_tail(&control->l, cntrl_list);
+
+		/* Configure control list item */
+		control->data = ext[i],
+		control->type = type;
+		control->owner = owner;
+		control->offset = *offset;
+		switch (control->data.type) {
+		case COUNTER_DATA_TYPE_U8:
+		case COUNTER_DATA_TYPE_BOOL:
+		case COUNTER_DATA_TYPE_COUNT_DIRECTION:
+		case COUNTER_DATA_TYPE_COUNT_MODE:
+			control->size = sizeof(u8);
+			break;
+		case COUNTER_DATA_TYPE_U64:
+			control->size = sizeof(u64);
+			break;
+		case COUNTER_DATA_TYPE_STRING:
+			control->size = 64;
+			break;
+		default:
+			err = -EINVAL;
+			goto err_control_ext_create;
+		}
+		*offset += control->size;
+	}
+
+	return 0;
+
+err_control_ext_create:
+	list_for_each_entry_safe_continue(p, n, cntrl_list, l) {
+		list_del(&p->l);
+		kfree(p);
+	}
+	return err;
+}
+
+static void counter_control_list_free(struct list_head *const cntrl_list)
+{
+	struct counter_control *p, *n;
+
+	list_for_each_entry_safe(p, n, cntrl_list, l) {
+		list_del(&p->l);
+		kfree(p);
+	}
+}
+
+static int counter_control_list_create(struct counter_device *const counter)
+{
+	const u8 *selection = counter->selection;
+	loff_t offset = COUNTER_SELECTION_SIZE;
+	size_t i, j;
+	struct counter_signal *signal;
+	struct counter_count *count;
+	struct counter_control *control;
+	int err;
+
+	/* Clean up old list */
+	counter_control_list_free(&counter->control_list);
+
+	/* Handle device extensions */
+	err = counter_control_ext_add(selection, COUNTER_OWNER_TYPE_DEVICE,
+				      NULL, counter->num_ext, counter->ext,
+				      &counter->control_list, &offset);
+	if (err)
+		goto err_control_create;
+	selection += counter->num_ext;
+
+	/* Handle Signals */
+	for (i = 0; i < counter->num_signals; i++) {
+		signal = counter->signals + i;
+
+		/* Check if Signal is selected */
+		if (*selection++) {
+			/* Generate control list item */
+			control = kzalloc(sizeof(*control), GFP_KERNEL);
+			if (!control) {
+				err = -ENOMEM;
+				goto err_control_create;
+			}
+			list_add_tail(&control->l, &counter->control_list);
+
+			/* Configure control list item */
+			control->data.type = COUNTER_DATA_TYPE_SIGNAL,
+			control->data.signal_u8_read = counter->signal_read;
+			control->type = COUNTER_OWNER_TYPE_SIGNAL;
+			control->owner = signal;
+			control->offset = offset;
+			control->size = sizeof(u8);
+			offset += control->size;
+		}
+
+		/* Handle extensions */
+		err = counter_control_ext_add(selection,
+					      COUNTER_OWNER_TYPE_SIGNAL, signal,
+					      signal->num_ext, signal->ext,
+					      &counter->control_list, &offset);
+		if (err)
+			goto err_control_create;
+		selection += signal->num_ext;
+	}
+
+	/* Handle Counts */
+	for (i = 0; i < counter->num_counts; i++) {
+		count = counter->counts + i;
+
+		/* Check if Count is selected */
+		if (*selection++) {
+			/* Generate control list item */
+			control = kzalloc(sizeof(*control), GFP_KERNEL);
+			if (!control) {
+				err = -ENOMEM;
+				goto err_control_create;
+			}
+			list_add_tail(&control->l, &counter->control_list);
+
+			/* Configure control list item */
+			control->data.type = COUNTER_DATA_TYPE_U64,
+			control->data.count_u64_read = counter->count_read;
+			control->data.count_u64_write = counter->count_write;
+			control->type = COUNTER_OWNER_TYPE_COUNT;
+			control->owner = count;
+			control->offset = offset;
+			control->size = sizeof(u64);
+			offset += control->size;
+		}
+
+		/* Handle count function */
+		if (*selection++) {
+			/* Generate control list item */
+			control = kzalloc(sizeof(*control), GFP_KERNEL);
+			if (!control) {
+				err = -ENOMEM;
+				goto err_control_create;
+			}
+			list_add_tail(&control->l, &counter->control_list);
+
+			/* Configure control list item */
+			control->data.type = COUNTER_DATA_TYPE_COUNT_FUNCTION,
+			control->data.count_u8_read = counter->function_read;
+			control->data.count_u8_write = counter->function_write;
+			control->type = COUNTER_OWNER_TYPE_COUNT;
+			control->owner = count;
+			control->offset = offset;
+			control->size = sizeof(u8);
+			offset += control->size;
+		}
+
+		/* Handle Synapses */
+		for (j = 0; j < count->num_synapses; j++) {
+			/* Check if extension is selected */
+			if (!*selection++)
+				continue;
+
+			/* Generate control list item */
+			control = kzalloc(sizeof(*control), GFP_KERNEL);
+			if (!control) {
+				err = -ENOMEM;
+				goto err_control_create;
+			}
+			list_add_tail(&control->l, &counter->control_list);
+
+			/* Configure control list item */
+			control->data.type = COUNTER_DATA_TYPE_SYNAPSE_ACTION;
+			control->data.action_read = counter->action_read;
+			control->data.action_write = counter->action_write;
+			control->data.priv = count->synapses + j;
+			control->type = COUNTER_OWNER_TYPE_COUNT;
+			control->owner = count;
+			control->offset = offset;
+			control->size = sizeof(u8);
+			offset += control->size;
+		}
+
+		/* Handle extensions */
+		err = counter_control_ext_add(selection,
+					      COUNTER_OWNER_TYPE_COUNT, count,
+					      count->num_ext, count->ext,
+					      &counter->control_list, &offset);
+		if (err)
+			goto err_control_create;
+		selection += count->num_ext;
+	}
+
+	return 0;
+
+err_control_create:
+	counter_control_list_free(&counter->control_list);
+	return err;
+}
+
+static int counter_data_u8_write(struct counter_device *const counter,
+				 const struct counter_control *const control,
+				 const u8 __user *const buf)
+{
+	const struct counter_data *const data = &control->data;
+	int err;
+	u8 val;
+
+	err = get_user(val, buf);
+	if (err)
+		return err;
+
+	switch (control->type) {
+	case COUNTER_OWNER_TYPE_DEVICE:
+		err = data->device_u8_write(counter, val);
+		break;
+	case COUNTER_OWNER_TYPE_SIGNAL:
+		err = data->signal_u8_write(counter, control->owner, val);
+		break;
+	case COUNTER_OWNER_TYPE_COUNT:
+		if (data->type == COUNTER_DATA_TYPE_SYNAPSE_ACTION)
+			err = data->action_write(counter, control->owner,
+						 data->priv, val);
+		else
+			err = data->count_u8_write(counter, control->owner,
+						   val);
+		break;
+	default: return -EINVAL;
+	}
+
+	return err;
+}
+
+static int counter_data_u64_write(struct counter_device *const counter,
+				  const struct counter_control *const control,
+				  const char __user *const buf,
+				  const size_t len, const size_t offset)
+{
+	const struct counter_data *const data = &control->data;
+	int err;
+	u64 val = 0;
+
+	err = copy_from_user((char *)&val + offset, buf, len);
+	if (err)
+		return err;
+
+	switch (control->type) {
+	case COUNTER_OWNER_TYPE_DEVICE:
+		err = data->device_u64_write(counter, val);
+		break;
+	case COUNTER_OWNER_TYPE_SIGNAL:
+		err = data->signal_u64_write(counter, control->owner, val);
+		break;
+	case COUNTER_OWNER_TYPE_COUNT:
+		err = data->count_u64_write(counter, control->owner, val);
+		break;
+	default: return -EINVAL;
+	}
+
+	return err;
+}
+
+static int counter_data_string_write(struct counter_device *const counter,
+				     const struct counter_control *const control,
+				     const char __user *const buf,
+				     const size_t len, const size_t offset)
+{
+	const struct counter_data *const data = &control->data;
+	int err;
+	char str[64] = "";
+
+	err = copy_from_user(str + offset, buf, len);
+	if (err)
+		return err;
+
+	switch (control->type) {
+	case COUNTER_OWNER_TYPE_DEVICE:
+		err = data->device_string_write(counter, str, sizeof(str));
+		break;
+	case COUNTER_OWNER_TYPE_SIGNAL:
+		err = data->signal_string_write(counter, control->owner, str,
+						sizeof(str));
+		break;
+	case COUNTER_OWNER_TYPE_COUNT:
+		err = data->count_string_write(counter, control->owner, str,
+					       sizeof(str));
+		break;
+	default: return -EINVAL;
+	}
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int counter_control_write(struct counter_device *const counter,
+				 const struct counter_control *const control,
+				 const char __user *const buf, const size_t len,
+				 const size_t offset)
+{
+	/* Check if write operation is supported */
+	if (!control->data.device_u8_write)
+		return -EFAULT;
+
+	switch (control->data.type) {
+	case COUNTER_DATA_TYPE_U8:
+	case COUNTER_DATA_TYPE_BOOL:
+	case COUNTER_DATA_TYPE_SIGNAL:
+	case COUNTER_DATA_TYPE_COUNT_FUNCTION:
+	case COUNTER_DATA_TYPE_SYNAPSE_ACTION:
+	case COUNTER_DATA_TYPE_COUNT_DIRECTION:
+	case COUNTER_DATA_TYPE_COUNT_MODE:
+		return counter_data_u8_write(counter, control, buf);
+	case COUNTER_DATA_TYPE_U64:
+		return counter_data_u64_write(counter, control, buf, len,
+					      offset);
+	case COUNTER_DATA_TYPE_STRING:
+		return counter_data_string_write(counter, control, buf, len,
+						 offset);
+	}
+
+	return -EINVAL;
+}
+
+static ssize_t counter_chrdev_write(struct file *filp, const char __user *buf,
+				    size_t len, loff_t *f_ps)
+{
+	const loff_t start_ps = *f_ps;
+	struct counter_device *const counter = filp->private_data;
+	size_t write_size;
+	struct counter_control *control;
+	int err;
+	loff_t next_control_ps;
+
+	/* Handle Counter control selection */
+	if (*f_ps < COUNTER_SELECTION_SIZE) {
+		write_size = (*f_ps + len > COUNTER_SELECTION_SIZE) ?
+			    COUNTER_SELECTION_SIZE - *f_ps : len;
+		if (copy_from_user(counter->selection + *f_ps, buf, write_size))
+			return -EFAULT;
+
+		/* Create new list based on updated selection array */
+		err = counter_control_list_create(counter);
+		if (err)
+			return err;
+
+		*f_ps += write_size;
+		buf += write_size;
+		len -= write_size;
+		if (!len)
+			goto exit_chrdev_write;
+	}
+
+	/* Handle controls */
+	list_for_each_entry(control, &counter->control_list, l) {
+		next_control_ps = control->offset + control->size;
+
+		/* Find first control item */
+		if (*f_ps >= next_control_ps)
+			continue;
+
+		write_size = (*f_ps + len > next_control_ps) ?
+			     next_control_ps - *f_ps : len;
+
+		err = counter_control_write(counter, control, buf, write_size,
+					    control->offset - *f_ps);
+		if (err)
+			return err;
+
+		*f_ps += write_size;
+		buf += write_size;
+		len -= write_size;
+		if (!len)
+			goto exit_chrdev_write;
+	}
+
+	return -EFAULT;
+
+exit_chrdev_write:
+	return *f_ps - start_ps;
+}
+
+static int counter_chrdev_open(struct inode *inode, struct file *filp)
+{
+	struct counter_device *const counter = container_of(inode->i_cdev,
+							    typeof(*counter),
+							    chrdev);
+
+	get_device(&counter->dev);
+	filp->private_data = counter;
+
+	return generic_file_open(inode, filp);
+}
+
+static int counter_chrdev_release(struct inode *inode, struct file *filp)
+{
+	struct counter_device *const counter = container_of(inode->i_cdev,
+							    typeof(*counter),
+							    chrdev);
+
+	put_device(&counter->dev);
+
+	return 0;
+}
+
+static const struct file_operations counter_fops = {
+	.llseek = generic_file_llseek,
+	.read = counter_chrdev_read,
+	.write = counter_chrdev_write,
+	.open = counter_chrdev_open,
+	.release = counter_chrdev_release,
+};
+
+int counter_chrdev_add(struct counter_device *const counter,
+		       const dev_t counter_devt)
+{
+	struct device *const dev = &counter->dev;
+	struct cdev *const chrdev = &counter->chrdev;
+
+	/* Initialize Counter character device control selection */
+	memset(counter->selection, 0, sizeof(counter->selection));
+
+	/* Initialize Counter character device selected controls list */
+	INIT_LIST_HEAD(&counter->control_list);
+
+	/* Initialize character device */
+	cdev_init(chrdev, &counter_fops);
+	dev->devt = MKDEV(MAJOR(counter_devt), counter->id);
+	cdev_set_parent(chrdev, &dev->kobj);
+
+	return cdev_add(chrdev, dev->devt, 1);
+}
+
+void counter_chrdev_free(struct counter_device *const counter)
+{
+	cdev_del(&counter->chrdev);
+	counter_control_list_free(&counter->control_list);
+}
diff --git a/drivers/counter/counter-chrdev.h b/drivers/counter/counter-chrdev.h
new file mode 100644
index 000000000000..7ab0797d3857
--- /dev/null
+++ b/drivers/counter/counter-chrdev.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Counter character device interface
+ * Copyright (C) 2020 William Breathitt Gray
+ */
+#ifndef _COUNTER_CHRDEV_H_
+#define _COUNTER_CHRDEV_H_
+
+#include <linux/counter.h>
+#include <linux/types.h>
+
+int counter_chrdev_add(struct counter_device *const counter,
+		       const dev_t counter_devt);
+void counter_chrdev_free(struct counter_device *const counter);
+
+#endif /* _COUNTER_CHRDEV_H_ */
diff --git a/drivers/counter/counter-core.c b/drivers/counter/counter-core.c
index 499664809c75..2d0886648201 100644
--- a/drivers/counter/counter-core.c
+++ b/drivers/counter/counter-core.c
@@ -6,11 +6,14 @@
 #include <linux/counter.h>
 #include <linux/device.h>
 #include <linux/export.h>
+#include <linux/fs.h>
 #include <linux/gfp.h>
 #include <linux/idr.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/types.h>
 
+#include "counter-chrdev.h"
 #include "counter-sysfs.h"
 
 /* Provides a unique ID for each counter device */
@@ -33,6 +36,8 @@ static struct bus_type counter_bus_type = {
 	.name = "counter"
 };
 
+static dev_t counter_devt;
+
 /**
  * counter_register - register Counter to the system
  * @counter:	pointer to Counter to register
@@ -62,10 +67,15 @@ int counter_register(struct counter_device *const counter)
 	device_initialize(dev);
 	dev_set_drvdata(dev, counter);
 
+	/* Add Counter character device */
+	err = counter_chrdev_add(counter, counter_devt);
+	if (err)
+		goto err_free_id;
+
 	/* Add Counter sysfs attributes */
 	err = counter_sysfs_add(counter);
 	if (err)
-		goto err_free_id;
+		goto err_free_chrdev;
 
 	/* Add device to system */
 	err = device_add(dev);
@@ -76,6 +86,8 @@ int counter_register(struct counter_device *const counter)
 
 err_free_sysfs:
 	counter_sysfs_free(counter);
+err_free_chrdev:
+	counter_chrdev_free(counter);
 err_free_id:
 	ida_simple_remove(&counter_ida, counter->id);
 	return err;
@@ -93,6 +105,7 @@ void counter_unregister(struct counter_device *const counter)
 	if (counter) {
 		device_del(&counter->dev);
 		counter_sysfs_free(counter);
+		counter_chrdev_free(counter);
 	}
 }
 EXPORT_SYMBOL_GPL(counter_unregister);
@@ -139,13 +152,30 @@ int devm_counter_register(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_counter_register);
 
+#define COUNTER_DEV_MAX 256
+
 static int __init counter_init(void)
 {
-	return bus_register(&counter_bus_type);
+	int err;
+
+	err = bus_register(&counter_bus_type);
+	if (err < 0)
+		return err;
+
+	err = alloc_chrdev_region(&counter_devt, 0, COUNTER_DEV_MAX, "counter");
+	if (err < 0)
+		goto err_unregister_bus;
+
+	return 0;
+
+err_unregister_bus:
+	bus_unregister(&counter_bus_type);
+	return err;
 }
 
 static void __exit counter_exit(void)
 {
+	unregister_chrdev_region(counter_devt, COUNTER_DEV_MAX);
 	bus_unregister(&counter_bus_type);
 }
 
diff --git a/include/linux/counter.h b/include/linux/counter.h
index e8abbaf47a4b..22e91d00a880 100644
--- a/include/linux/counter.h
+++ b/include/linux/counter.h
@@ -6,6 +6,7 @@
 #ifndef _COUNTER_H_
 #define _COUNTER_H_
 
+#include <linux/cdev.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -170,6 +171,9 @@ struct counter_attribute_group {
  * @priv:		optional private data supplied by driver
  * @id:			unique ID used to identify the Counter
  * @dev:		internal device structure
+ * @chrdev:		internal character device structure
+ * @selection:		Counter character device control selection
+ * @control_list:	Counter character device selected controls
  * @dynamic_names_list:	List for dynamic names
  * @groups_list:	attribute groups list (for Signals, Counts, and ext)
  * @num_groups:		number of attribute groups containers
@@ -208,6 +212,18 @@ struct counter_device {
 
 	int id;
 	struct device dev;
+	struct cdev chrdev;
+
+#define MAX_EXT 255
+#define MAX_SIGNALS 255
+#define MAX_SYNAPSES 255
+#define MAX_COUNTS 255
+#define SIGNALS_SELECTION_SIZE ((1 + MAX_EXT) * MAX_SIGNALS)
+#define COUNTS_SELECTION_SIZE ((1 + 1 + MAX_SYNAPSES + MAX_EXT) * MAX_COUNTS)
+#define COUNTER_SELECTION_SIZE (MAX_EXT + SIGNALS_SELECTION_SIZE + COUNTS_SELECTION_SIZE)
+	u8 selection[COUNTER_SELECTION_SIZE];
+	struct list_head control_list;
+
 	struct list_head dynamic_names_list;
 	struct counter_attribute_group *groups_list;
 	size_t num_groups;
