0001
0002
0003
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");