summaryrefslogtreecommitdiffstats
path: root/drivers/counter/intel-qep.c
diff options
context:
space:
mode:
authorWilliam Breathitt Gray <vilhelm.gray@gmail.com>2021-08-27 12:47:47 +0900
committerJonathan Cameron <Jonathan.Cameron@huawei.com>2021-10-17 10:52:58 +0100
commitaaec1a0f76ec25f46bbb17b81487c4b0e1c318c5 (patch)
treeb76c9daf90cf5f493fc865aca6dc8ed8a9798ea0 /drivers/counter/intel-qep.c
parentea434ff82649111de4fcabd76187270f8abdb63a (diff)
downloadlinux-aaec1a0f76ec25f46bbb17b81487c4b0e1c318c5.tar.bz2
counter: Internalize sysfs interface code
This is a reimplementation of the Generic Counter driver interface. There are no modifications to the Counter subsystem userspace interface, so existing userspace applications should continue to run seamlessly. The purpose of this patch is to internalize the sysfs interface code among the various counter drivers into a shared module. Counter drivers pass and take data natively (i.e. u8, u64, etc.) and the shared counter module handles the translation between the sysfs interface and the device drivers. This guarantees a standard userspace interface for all counter drivers, and helps generalize the Generic Counter driver ABI in order to support the Generic Counter chrdev interface (introduced in a subsequent patch) without significant changes to the existing counter drivers. Note, Counter device registration is the same as before: drivers populate a struct counter_device with components and callbacks, then pass the structure to the devm_counter_register function. However, what's different now is how the Counter subsystem code handles this registration internally. Whereas before callbacks would interact directly with sysfs data, this interaction is now abstracted and instead callbacks interact with native C data types. The counter_comp structure forms the basis for Counter extensions. The counter-sysfs.c file contains the code to parse through the counter_device structure and register the requested components and extensions. Attributes are created and populated based on type, with respective translation functions to handle the mapping between sysfs and the counter driver callbacks. The translation performed for each attribute is straightforward: the attribute type and data is parsed from the counter_attribute structure, the respective counter driver read/write callback is called, and sysfs I/O is handled before or after the driver read/write function is called. Cc: Jarkko Nikula <jarkko.nikula@linux.intel.com> Cc: Patrick Havelange <patrick.havelange@essensium.com> Cc: Kamel Bouhara <kamel.bouhara@bootlin.com> Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com> Cc: Alexandre Torgue <alexandre.torgue@st.com> Cc: Dan Carpenter <dan.carpenter@oracle.com> Acked-by: Syed Nayyar Waris <syednwaris@gmail.com> Reviewed-by: David Lechner <david@lechnology.com> Tested-by: David Lechner <david@lechnology.com> Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com> Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com> # for stm32 Link: https://lore.kernel.org/r/c68b4a1ffb195c1a2f65e8dd5ad7b7c14e79c6ef.1630031207.git.vilhelm.gray@gmail.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Diffstat (limited to 'drivers/counter/intel-qep.c')
-rw-r--r--drivers/counter/intel-qep.c146
1 files changed, 62 insertions, 84 deletions
diff --git a/drivers/counter/intel-qep.c b/drivers/counter/intel-qep.c
index 8a6847d5fb2b..0924d16de6e2 100644
--- a/drivers/counter/intel-qep.c
+++ b/drivers/counter/intel-qep.c
@@ -62,13 +62,6 @@
#define INTEL_QEP_CLK_PERIOD_NS 10
-#define INTEL_QEP_COUNTER_EXT_RW(_name) \
-{ \
- .name = #_name, \
- .read = _name##_read, \
- .write = _name##_write, \
-}
-
struct intel_qep {
struct counter_device counter;
struct mutex lock;
@@ -114,8 +107,7 @@ static void intel_qep_init(struct intel_qep *qep)
}
static int intel_qep_count_read(struct counter_device *counter,
- struct counter_count *count,
- unsigned long *val)
+ struct counter_count *count, u64 *val)
{
struct intel_qep *const qep = counter->priv;
@@ -130,11 +122,11 @@ static const enum counter_function intel_qep_count_functions[] = {
COUNTER_FUNCTION_QUADRATURE_X4,
};
-static int intel_qep_function_get(struct counter_device *counter,
- struct counter_count *count,
- size_t *function)
+static int intel_qep_function_read(struct counter_device *counter,
+ struct counter_count *count,
+ enum counter_function *function)
{
- *function = 0;
+ *function = COUNTER_FUNCTION_QUADRATURE_X4;
return 0;
}
@@ -143,19 +135,19 @@ static const enum counter_synapse_action intel_qep_synapse_actions[] = {
COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
};
-static int intel_qep_action_get(struct counter_device *counter,
- struct counter_count *count,
- struct counter_synapse *synapse,
- size_t *action)
+static int intel_qep_action_read(struct counter_device *counter,
+ struct counter_count *count,
+ struct counter_synapse *synapse,
+ enum counter_synapse_action *action)
{
- *action = 0;
+ *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
return 0;
}
static const struct counter_ops intel_qep_counter_ops = {
.count_read = intel_qep_count_read,
- .function_get = intel_qep_function_get,
- .action_get = intel_qep_action_get,
+ .function_read = intel_qep_function_read,
+ .action_read = intel_qep_action_read,
};
#define INTEL_QEP_SIGNAL(_id, _name) { \
@@ -181,31 +173,27 @@ static struct counter_synapse intel_qep_count_synapses[] = {
INTEL_QEP_SYNAPSE(2),
};
-static ssize_t ceiling_read(struct counter_device *counter,
- struct counter_count *count,
- void *priv, char *buf)
+static int intel_qep_ceiling_read(struct counter_device *counter,
+ struct counter_count *count, u64 *ceiling)
{
struct intel_qep *qep = counter->priv;
- u32 reg;
pm_runtime_get_sync(qep->dev);
- reg = intel_qep_readl(qep, INTEL_QEPMAX);
+ *ceiling = intel_qep_readl(qep, INTEL_QEPMAX);
pm_runtime_put(qep->dev);
- return sysfs_emit(buf, "%u\n", reg);
+ return 0;
}
-static ssize_t ceiling_write(struct counter_device *counter,
- struct counter_count *count,
- void *priv, const char *buf, size_t len)
+static int intel_qep_ceiling_write(struct counter_device *counter,
+ struct counter_count *count, u64 max)
{
struct intel_qep *qep = counter->priv;
- u32 max;
- int ret;
+ int ret = 0;
- ret = kstrtou32(buf, 0, &max);
- if (ret < 0)
- return ret;
+ /* Intel QEP ceiling configuration only supports 32-bit values */
+ if (max != (u32)max)
+ return -ERANGE;
mutex_lock(&qep->lock);
if (qep->enabled) {
@@ -216,34 +204,28 @@ static ssize_t ceiling_write(struct counter_device *counter,
pm_runtime_get_sync(qep->dev);
intel_qep_writel(qep, INTEL_QEPMAX, max);
pm_runtime_put(qep->dev);
- ret = len;
out:
mutex_unlock(&qep->lock);
return ret;
}
-static ssize_t enable_read(struct counter_device *counter,
- struct counter_count *count,
- void *priv, char *buf)
+static int intel_qep_enable_read(struct counter_device *counter,
+ struct counter_count *count, u8 *enable)
{
struct intel_qep *qep = counter->priv;
- return sysfs_emit(buf, "%u\n", qep->enabled);
+ *enable = qep->enabled;
+
+ return 0;
}
-static ssize_t enable_write(struct counter_device *counter,
- struct counter_count *count,
- void *priv, const char *buf, size_t len)
+static int intel_qep_enable_write(struct counter_device *counter,
+ struct counter_count *count, u8 val)
{
struct intel_qep *qep = counter->priv;
u32 reg;
- bool val, changed;
- int ret;
-
- ret = kstrtobool(buf, &val);
- if (ret)
- return ret;
+ bool changed;
mutex_lock(&qep->lock);
changed = val ^ qep->enabled;
@@ -267,12 +249,12 @@ static ssize_t enable_write(struct counter_device *counter,
out:
mutex_unlock(&qep->lock);
- return len;
+ return 0;
}
-static ssize_t spike_filter_ns_read(struct counter_device *counter,
- struct counter_count *count,
- void *priv, char *buf)
+static int intel_qep_spike_filter_ns_read(struct counter_device *counter,
+ struct counter_count *count,
+ u64 *length)
{
struct intel_qep *qep = counter->priv;
u32 reg;
@@ -281,33 +263,31 @@ static ssize_t spike_filter_ns_read(struct counter_device *counter,
reg = intel_qep_readl(qep, INTEL_QEPCON);
if (!(reg & INTEL_QEPCON_FLT_EN)) {
pm_runtime_put(qep->dev);
- return sysfs_emit(buf, "0\n");
+ return 0;
}
reg = INTEL_QEPFLT_MAX_COUNT(intel_qep_readl(qep, INTEL_QEPFLT));
pm_runtime_put(qep->dev);
- return sysfs_emit(buf, "%u\n", (reg + 2) * INTEL_QEP_CLK_PERIOD_NS);
+ *length = (reg + 2) * INTEL_QEP_CLK_PERIOD_NS;
+
+ return 0;
}
-static ssize_t spike_filter_ns_write(struct counter_device *counter,
- struct counter_count *count,
- void *priv, const char *buf, size_t len)
+static int intel_qep_spike_filter_ns_write(struct counter_device *counter,
+ struct counter_count *count,
+ u64 length)
{
struct intel_qep *qep = counter->priv;
- u32 reg, length;
+ u32 reg;
bool enable;
- int ret;
-
- ret = kstrtou32(buf, 0, &length);
- if (ret < 0)
- return ret;
+ int ret = 0;
/*
* Spike filter length is (MAX_COUNT + 2) clock periods.
* Disable filter when userspace writes 0, enable for valid
* nanoseconds values and error out otherwise.
*/
- length /= INTEL_QEP_CLK_PERIOD_NS;
+ do_div(length, INTEL_QEP_CLK_PERIOD_NS);
if (length == 0) {
enable = false;
length = 0;
@@ -336,16 +316,15 @@ static ssize_t spike_filter_ns_write(struct counter_device *counter,
intel_qep_writel(qep, INTEL_QEPFLT, length);
intel_qep_writel(qep, INTEL_QEPCON, reg);
pm_runtime_put(qep->dev);
- ret = len;
out:
mutex_unlock(&qep->lock);
return ret;
}
-static ssize_t preset_enable_read(struct counter_device *counter,
- struct counter_count *count,
- void *priv, char *buf)
+static int intel_qep_preset_enable_read(struct counter_device *counter,
+ struct counter_count *count,
+ u8 *preset_enable)
{
struct intel_qep *qep = counter->priv;
u32 reg;
@@ -353,21 +332,18 @@ static ssize_t preset_enable_read(struct counter_device *counter,
pm_runtime_get_sync(qep->dev);
reg = intel_qep_readl(qep, INTEL_QEPCON);
pm_runtime_put(qep->dev);
- return sysfs_emit(buf, "%u\n", !(reg & INTEL_QEPCON_COUNT_RST_MODE));
+
+ *preset_enable = !(reg & INTEL_QEPCON_COUNT_RST_MODE);
+
+ return 0;
}
-static ssize_t preset_enable_write(struct counter_device *counter,
- struct counter_count *count,
- void *priv, const char *buf, size_t len)
+static int intel_qep_preset_enable_write(struct counter_device *counter,
+ struct counter_count *count, u8 val)
{
struct intel_qep *qep = counter->priv;
u32 reg;
- bool val;
- int ret;
-
- ret = kstrtobool(buf, &val);
- if (ret)
- return ret;
+ int ret = 0;
mutex_lock(&qep->lock);
if (qep->enabled) {
@@ -384,7 +360,6 @@ static ssize_t preset_enable_write(struct counter_device *counter,
intel_qep_writel(qep, INTEL_QEPCON, reg);
pm_runtime_put(qep->dev);
- ret = len;
out:
mutex_unlock(&qep->lock);
@@ -392,11 +367,14 @@ out:
return ret;
}
-static const struct counter_count_ext intel_qep_count_ext[] = {
- INTEL_QEP_COUNTER_EXT_RW(ceiling),
- INTEL_QEP_COUNTER_EXT_RW(enable),
- INTEL_QEP_COUNTER_EXT_RW(spike_filter_ns),
- INTEL_QEP_COUNTER_EXT_RW(preset_enable)
+static struct counter_comp intel_qep_count_ext[] = {
+ COUNTER_COMP_ENABLE(intel_qep_enable_read, intel_qep_enable_write),
+ COUNTER_COMP_CEILING(intel_qep_ceiling_read, intel_qep_ceiling_write),
+ COUNTER_COMP_PRESET_ENABLE(intel_qep_preset_enable_read,
+ intel_qep_preset_enable_write),
+ COUNTER_COMP_COUNT_U64("spike_filter_ns",
+ intel_qep_spike_filter_ns_read,
+ intel_qep_spike_filter_ns_write),
};
static struct counter_count intel_qep_counter_count[] = {