Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2021 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
0004  */
0005 
0006 #include <linux/counter.h>
0007 #include <linux/gpio/consumer.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/irq.h>
0010 #include <linux/mod_devicetable.h>
0011 #include <linux/module.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/types.h>
0014 
0015 #define INTERRUPT_CNT_NAME "interrupt-cnt"
0016 
0017 struct interrupt_cnt_priv {
0018     atomic_t count;
0019     struct gpio_desc *gpio;
0020     int irq;
0021     bool enabled;
0022     struct counter_signal signals;
0023     struct counter_synapse synapses;
0024     struct counter_count cnts;
0025 };
0026 
0027 static irqreturn_t interrupt_cnt_isr(int irq, void *dev_id)
0028 {
0029     struct counter_device *counter = dev_id;
0030     struct interrupt_cnt_priv *priv = counter_priv(counter);
0031 
0032     atomic_inc(&priv->count);
0033 
0034     counter_push_event(counter, COUNTER_EVENT_CHANGE_OF_STATE, 0);
0035 
0036     return IRQ_HANDLED;
0037 }
0038 
0039 static int interrupt_cnt_enable_read(struct counter_device *counter,
0040                      struct counter_count *count, u8 *enable)
0041 {
0042     struct interrupt_cnt_priv *priv = counter_priv(counter);
0043 
0044     *enable = priv->enabled;
0045 
0046     return 0;
0047 }
0048 
0049 static int interrupt_cnt_enable_write(struct counter_device *counter,
0050                       struct counter_count *count, u8 enable)
0051 {
0052     struct interrupt_cnt_priv *priv = counter_priv(counter);
0053 
0054     if (priv->enabled == enable)
0055         return 0;
0056 
0057     if (enable) {
0058         priv->enabled = true;
0059         enable_irq(priv->irq);
0060     } else {
0061         disable_irq(priv->irq);
0062         priv->enabled = false;
0063     }
0064 
0065     return 0;
0066 }
0067 
0068 static struct counter_comp interrupt_cnt_ext[] = {
0069     COUNTER_COMP_ENABLE(interrupt_cnt_enable_read,
0070                 interrupt_cnt_enable_write),
0071 };
0072 
0073 static const enum counter_synapse_action interrupt_cnt_synapse_actions[] = {
0074     COUNTER_SYNAPSE_ACTION_RISING_EDGE,
0075 };
0076 
0077 static int interrupt_cnt_action_read(struct counter_device *counter,
0078                      struct counter_count *count,
0079                      struct counter_synapse *synapse,
0080                      enum counter_synapse_action *action)
0081 {
0082     *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
0083 
0084     return 0;
0085 }
0086 
0087 static int interrupt_cnt_read(struct counter_device *counter,
0088                   struct counter_count *count, u64 *val)
0089 {
0090     struct interrupt_cnt_priv *priv = counter_priv(counter);
0091 
0092     *val = atomic_read(&priv->count);
0093 
0094     return 0;
0095 }
0096 
0097 static int interrupt_cnt_write(struct counter_device *counter,
0098                    struct counter_count *count, const u64 val)
0099 {
0100     struct interrupt_cnt_priv *priv = counter_priv(counter);
0101 
0102     if (val != (typeof(priv->count.counter))val)
0103         return -ERANGE;
0104 
0105     atomic_set(&priv->count, val);
0106 
0107     return 0;
0108 }
0109 
0110 static const enum counter_function interrupt_cnt_functions[] = {
0111     COUNTER_FUNCTION_INCREASE,
0112 };
0113 
0114 static int interrupt_cnt_function_read(struct counter_device *counter,
0115                        struct counter_count *count,
0116                        enum counter_function *function)
0117 {
0118     *function = COUNTER_FUNCTION_INCREASE;
0119 
0120     return 0;
0121 }
0122 
0123 static int interrupt_cnt_signal_read(struct counter_device *counter,
0124                      struct counter_signal *signal,
0125                      enum counter_signal_level *level)
0126 {
0127     struct interrupt_cnt_priv *priv = counter_priv(counter);
0128     int ret;
0129 
0130     if (!priv->gpio)
0131         return -EINVAL;
0132 
0133     ret = gpiod_get_value(priv->gpio);
0134     if (ret < 0)
0135         return ret;
0136 
0137     *level = ret ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
0138 
0139     return 0;
0140 }
0141 
0142 static const struct counter_ops interrupt_cnt_ops = {
0143     .action_read = interrupt_cnt_action_read,
0144     .count_read = interrupt_cnt_read,
0145     .count_write = interrupt_cnt_write,
0146     .function_read = interrupt_cnt_function_read,
0147     .signal_read  = interrupt_cnt_signal_read,
0148 };
0149 
0150 static int interrupt_cnt_probe(struct platform_device *pdev)
0151 {
0152     struct device *dev = &pdev->dev;
0153     struct counter_device *counter;
0154     struct interrupt_cnt_priv *priv;
0155     int ret;
0156 
0157     counter = devm_counter_alloc(dev, sizeof(*priv));
0158     if (!counter)
0159         return -ENOMEM;
0160     priv = counter_priv(counter);
0161 
0162     priv->irq = platform_get_irq_optional(pdev,  0);
0163     if (priv->irq == -ENXIO)
0164         priv->irq = 0;
0165     else if (priv->irq < 0)
0166         return dev_err_probe(dev, priv->irq, "failed to get IRQ\n");
0167 
0168     priv->gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_IN);
0169     if (IS_ERR(priv->gpio))
0170         return dev_err_probe(dev, PTR_ERR(priv->gpio), "failed to get GPIO\n");
0171 
0172     if (!priv->irq && !priv->gpio) {
0173         dev_err(dev, "IRQ and GPIO are not found. At least one source should be provided\n");
0174         return -ENODEV;
0175     }
0176 
0177     if (!priv->irq) {
0178         int irq = gpiod_to_irq(priv->gpio);
0179 
0180         if (irq < 0)
0181             return dev_err_probe(dev, irq, "failed to get IRQ from GPIO\n");
0182 
0183         priv->irq = irq;
0184     }
0185 
0186     priv->signals.name = devm_kasprintf(dev, GFP_KERNEL, "IRQ %d",
0187                         priv->irq);
0188     if (!priv->signals.name)
0189         return -ENOMEM;
0190 
0191     counter->signals = &priv->signals;
0192     counter->num_signals = 1;
0193 
0194     priv->synapses.actions_list = interrupt_cnt_synapse_actions;
0195     priv->synapses.num_actions = ARRAY_SIZE(interrupt_cnt_synapse_actions);
0196     priv->synapses.signal = &priv->signals;
0197 
0198     priv->cnts.name = "Channel 0 Count";
0199     priv->cnts.functions_list = interrupt_cnt_functions;
0200     priv->cnts.num_functions = ARRAY_SIZE(interrupt_cnt_functions);
0201     priv->cnts.synapses = &priv->synapses;
0202     priv->cnts.num_synapses = 1;
0203     priv->cnts.ext = interrupt_cnt_ext;
0204     priv->cnts.num_ext = ARRAY_SIZE(interrupt_cnt_ext);
0205 
0206     counter->name = dev_name(dev);
0207     counter->parent = dev;
0208     counter->ops = &interrupt_cnt_ops;
0209     counter->counts = &priv->cnts;
0210     counter->num_counts = 1;
0211 
0212     irq_set_status_flags(priv->irq, IRQ_NOAUTOEN);
0213     ret = devm_request_irq(dev, priv->irq, interrupt_cnt_isr,
0214                    IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
0215                    dev_name(dev), counter);
0216     if (ret)
0217         return ret;
0218 
0219     ret = devm_counter_add(dev, counter);
0220     if (ret < 0)
0221         return dev_err_probe(dev, ret, "Failed to add counter\n");
0222 
0223     return 0;
0224 }
0225 
0226 static const struct of_device_id interrupt_cnt_of_match[] = {
0227     { .compatible = "interrupt-counter", },
0228     {}
0229 };
0230 MODULE_DEVICE_TABLE(of, interrupt_cnt_of_match);
0231 
0232 static struct platform_driver interrupt_cnt_driver = {
0233     .probe = interrupt_cnt_probe,
0234     .driver = {
0235         .name = INTERRUPT_CNT_NAME,
0236         .of_match_table = interrupt_cnt_of_match,
0237     },
0238 };
0239 module_platform_driver(interrupt_cnt_driver);
0240 
0241 MODULE_ALIAS("platform:interrupt-counter");
0242 MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
0243 MODULE_DESCRIPTION("Interrupt counter driver");
0244 MODULE_LICENSE("GPL v2");