Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2020 Microchip
0004  *
0005  * Author: Kamel Bouhara <kamel.bouhara@bootlin.com>
0006  */
0007 #include <linux/clk.h>
0008 #include <linux/counter.h>
0009 #include <linux/mfd/syscon.h>
0010 #include <linux/module.h>
0011 #include <linux/mutex.h>
0012 #include <linux/of.h>
0013 #include <linux/of_device.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/regmap.h>
0016 #include <soc/at91/atmel_tcb.h>
0017 
0018 #define ATMEL_TC_CMR_MASK   (ATMEL_TC_LDRA_RISING | ATMEL_TC_LDRB_FALLING | \
0019                  ATMEL_TC_ETRGEDG_RISING | ATMEL_TC_LDBDIS | \
0020                  ATMEL_TC_LDBSTOP)
0021 
0022 #define ATMEL_TC_QDEN           BIT(8)
0023 #define ATMEL_TC_POSEN          BIT(9)
0024 
0025 struct mchp_tc_data {
0026     const struct atmel_tcb_config *tc_cfg;
0027     struct regmap *regmap;
0028     int qdec_mode;
0029     int num_channels;
0030     int channel[2];
0031     bool trig_inverted;
0032 };
0033 
0034 static const enum counter_function mchp_tc_count_functions[] = {
0035     COUNTER_FUNCTION_INCREASE,
0036     COUNTER_FUNCTION_QUADRATURE_X4,
0037 };
0038 
0039 static const enum counter_synapse_action mchp_tc_synapse_actions[] = {
0040     COUNTER_SYNAPSE_ACTION_NONE,
0041     COUNTER_SYNAPSE_ACTION_RISING_EDGE,
0042     COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
0043     COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
0044 };
0045 
0046 static struct counter_signal mchp_tc_count_signals[] = {
0047     {
0048         .id = 0,
0049         .name = "Channel A",
0050     },
0051     {
0052         .id = 1,
0053         .name = "Channel B",
0054     }
0055 };
0056 
0057 static struct counter_synapse mchp_tc_count_synapses[] = {
0058     {
0059         .actions_list = mchp_tc_synapse_actions,
0060         .num_actions = ARRAY_SIZE(mchp_tc_synapse_actions),
0061         .signal = &mchp_tc_count_signals[0]
0062     },
0063     {
0064         .actions_list = mchp_tc_synapse_actions,
0065         .num_actions = ARRAY_SIZE(mchp_tc_synapse_actions),
0066         .signal = &mchp_tc_count_signals[1]
0067     }
0068 };
0069 
0070 static int mchp_tc_count_function_read(struct counter_device *counter,
0071                        struct counter_count *count,
0072                        enum counter_function *function)
0073 {
0074     struct mchp_tc_data *const priv = counter_priv(counter);
0075 
0076     if (priv->qdec_mode)
0077         *function = COUNTER_FUNCTION_QUADRATURE_X4;
0078     else
0079         *function = COUNTER_FUNCTION_INCREASE;
0080 
0081     return 0;
0082 }
0083 
0084 static int mchp_tc_count_function_write(struct counter_device *counter,
0085                     struct counter_count *count,
0086                     enum counter_function function)
0087 {
0088     struct mchp_tc_data *const priv = counter_priv(counter);
0089     u32 bmr, cmr;
0090 
0091     regmap_read(priv->regmap, ATMEL_TC_BMR, &bmr);
0092     regmap_read(priv->regmap, ATMEL_TC_REG(priv->channel[0], CMR), &cmr);
0093 
0094     /* Set capture mode */
0095     cmr &= ~ATMEL_TC_WAVE;
0096 
0097     switch (function) {
0098     case COUNTER_FUNCTION_INCREASE:
0099         priv->qdec_mode = 0;
0100         /* Set highest rate based on whether soc has gclk or not */
0101         bmr &= ~(ATMEL_TC_QDEN | ATMEL_TC_POSEN);
0102         if (priv->tc_cfg->has_gclk)
0103             cmr |= ATMEL_TC_TIMER_CLOCK2;
0104         else
0105             cmr |= ATMEL_TC_TIMER_CLOCK1;
0106         /* Setup the period capture mode */
0107         cmr |=  ATMEL_TC_CMR_MASK;
0108         cmr &= ~(ATMEL_TC_ABETRG | ATMEL_TC_XC0);
0109         break;
0110     case COUNTER_FUNCTION_QUADRATURE_X4:
0111         if (!priv->tc_cfg->has_qdec)
0112             return -EINVAL;
0113         /* In QDEC mode settings both channels 0 and 1 are required */
0114         if (priv->num_channels < 2 || priv->channel[0] != 0 ||
0115             priv->channel[1] != 1) {
0116             pr_err("Invalid channels number or id for quadrature mode\n");
0117             return -EINVAL;
0118         }
0119         priv->qdec_mode = 1;
0120         bmr |= ATMEL_TC_QDEN | ATMEL_TC_POSEN;
0121         cmr |= ATMEL_TC_ETRGEDG_RISING | ATMEL_TC_ABETRG | ATMEL_TC_XC0;
0122         break;
0123     default:
0124         /* should never reach this path */
0125         return -EINVAL;
0126     }
0127 
0128     regmap_write(priv->regmap, ATMEL_TC_BMR, bmr);
0129     regmap_write(priv->regmap, ATMEL_TC_REG(priv->channel[0], CMR), cmr);
0130 
0131     /* Enable clock and trigger counter */
0132     regmap_write(priv->regmap, ATMEL_TC_REG(priv->channel[0], CCR),
0133              ATMEL_TC_CLKEN | ATMEL_TC_SWTRG);
0134 
0135     if (priv->qdec_mode) {
0136         regmap_write(priv->regmap,
0137                  ATMEL_TC_REG(priv->channel[1], CMR), cmr);
0138         regmap_write(priv->regmap,
0139                  ATMEL_TC_REG(priv->channel[1], CCR),
0140                  ATMEL_TC_CLKEN | ATMEL_TC_SWTRG);
0141     }
0142 
0143     return 0;
0144 }
0145 
0146 static int mchp_tc_count_signal_read(struct counter_device *counter,
0147                      struct counter_signal *signal,
0148                      enum counter_signal_level *lvl)
0149 {
0150     struct mchp_tc_data *const priv = counter_priv(counter);
0151     bool sigstatus;
0152     u32 sr;
0153 
0154     regmap_read(priv->regmap, ATMEL_TC_REG(priv->channel[0], SR), &sr);
0155 
0156     if (priv->trig_inverted)
0157         sigstatus = (sr & ATMEL_TC_MTIOB);
0158     else
0159         sigstatus = (sr & ATMEL_TC_MTIOA);
0160 
0161     *lvl = sigstatus ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
0162 
0163     return 0;
0164 }
0165 
0166 static int mchp_tc_count_action_read(struct counter_device *counter,
0167                      struct counter_count *count,
0168                      struct counter_synapse *synapse,
0169                      enum counter_synapse_action *action)
0170 {
0171     struct mchp_tc_data *const priv = counter_priv(counter);
0172     u32 cmr;
0173 
0174     regmap_read(priv->regmap, ATMEL_TC_REG(priv->channel[0], CMR), &cmr);
0175 
0176     switch (cmr & ATMEL_TC_ETRGEDG) {
0177     default:
0178         *action = COUNTER_SYNAPSE_ACTION_NONE;
0179         break;
0180     case ATMEL_TC_ETRGEDG_RISING:
0181         *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
0182         break;
0183     case ATMEL_TC_ETRGEDG_FALLING:
0184         *action = COUNTER_SYNAPSE_ACTION_FALLING_EDGE;
0185         break;
0186     case ATMEL_TC_ETRGEDG_BOTH:
0187         *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
0188         break;
0189     }
0190 
0191     return 0;
0192 }
0193 
0194 static int mchp_tc_count_action_write(struct counter_device *counter,
0195                       struct counter_count *count,
0196                       struct counter_synapse *synapse,
0197                       enum counter_synapse_action action)
0198 {
0199     struct mchp_tc_data *const priv = counter_priv(counter);
0200     u32 edge = ATMEL_TC_ETRGEDG_NONE;
0201 
0202     /* QDEC mode is rising edge only */
0203     if (priv->qdec_mode)
0204         return -EINVAL;
0205 
0206     switch (action) {
0207     case COUNTER_SYNAPSE_ACTION_NONE:
0208         edge = ATMEL_TC_ETRGEDG_NONE;
0209         break;
0210     case COUNTER_SYNAPSE_ACTION_RISING_EDGE:
0211         edge = ATMEL_TC_ETRGEDG_RISING;
0212         break;
0213     case COUNTER_SYNAPSE_ACTION_FALLING_EDGE:
0214         edge = ATMEL_TC_ETRGEDG_FALLING;
0215         break;
0216     case COUNTER_SYNAPSE_ACTION_BOTH_EDGES:
0217         edge = ATMEL_TC_ETRGEDG_BOTH;
0218         break;
0219     default:
0220         /* should never reach this path */
0221         return -EINVAL;
0222     }
0223 
0224     return regmap_write_bits(priv->regmap,
0225                 ATMEL_TC_REG(priv->channel[0], CMR),
0226                 ATMEL_TC_ETRGEDG, edge);
0227 }
0228 
0229 static int mchp_tc_count_read(struct counter_device *counter,
0230                   struct counter_count *count, u64 *val)
0231 {
0232     struct mchp_tc_data *const priv = counter_priv(counter);
0233     u32 cnt;
0234 
0235     regmap_read(priv->regmap, ATMEL_TC_REG(priv->channel[0], CV), &cnt);
0236     *val = cnt;
0237 
0238     return 0;
0239 }
0240 
0241 static struct counter_count mchp_tc_counts[] = {
0242     {
0243         .id = 0,
0244         .name = "Timer Counter",
0245         .functions_list = mchp_tc_count_functions,
0246         .num_functions = ARRAY_SIZE(mchp_tc_count_functions),
0247         .synapses = mchp_tc_count_synapses,
0248         .num_synapses = ARRAY_SIZE(mchp_tc_count_synapses),
0249     },
0250 };
0251 
0252 static const struct counter_ops mchp_tc_ops = {
0253     .signal_read    = mchp_tc_count_signal_read,
0254     .count_read     = mchp_tc_count_read,
0255     .function_read  = mchp_tc_count_function_read,
0256     .function_write = mchp_tc_count_function_write,
0257     .action_read    = mchp_tc_count_action_read,
0258     .action_write   = mchp_tc_count_action_write
0259 };
0260 
0261 static const struct atmel_tcb_config tcb_rm9200_config = {
0262         .counter_width = 16,
0263 };
0264 
0265 static const struct atmel_tcb_config tcb_sam9x5_config = {
0266         .counter_width = 32,
0267 };
0268 
0269 static const struct atmel_tcb_config tcb_sama5d2_config = {
0270         .counter_width = 32,
0271         .has_gclk = true,
0272         .has_qdec = true,
0273 };
0274 
0275 static const struct atmel_tcb_config tcb_sama5d3_config = {
0276         .counter_width = 32,
0277         .has_qdec = true,
0278 };
0279 
0280 static const struct of_device_id atmel_tc_of_match[] = {
0281     { .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, },
0282     { .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, },
0283     { .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, },
0284     { .compatible = "atmel,sama5d3-tcb", .data = &tcb_sama5d3_config, },
0285     { /* sentinel */ }
0286 };
0287 
0288 static void mchp_tc_clk_remove(void *ptr)
0289 {
0290     clk_disable_unprepare((struct clk *)ptr);
0291 }
0292 
0293 static int mchp_tc_probe(struct platform_device *pdev)
0294 {
0295     struct device_node *np = pdev->dev.of_node;
0296     const struct atmel_tcb_config *tcb_config;
0297     const struct of_device_id *match;
0298     struct counter_device *counter;
0299     struct mchp_tc_data *priv;
0300     char clk_name[7];
0301     struct regmap *regmap;
0302     struct clk *clk[3];
0303     int channel;
0304     int ret, i;
0305 
0306     counter = devm_counter_alloc(&pdev->dev, sizeof(*priv));
0307     if (!counter)
0308         return -ENOMEM;
0309     priv = counter_priv(counter);
0310 
0311     match = of_match_node(atmel_tc_of_match, np->parent);
0312     tcb_config = match->data;
0313     if (!tcb_config) {
0314         dev_err(&pdev->dev, "No matching parent node found\n");
0315         return -ENODEV;
0316     }
0317 
0318     regmap = syscon_node_to_regmap(np->parent);
0319     if (IS_ERR(regmap))
0320         return PTR_ERR(regmap);
0321 
0322     /* max. channels number is 2 when in QDEC mode */
0323     priv->num_channels = of_property_count_u32_elems(np, "reg");
0324     if (priv->num_channels < 0) {
0325         dev_err(&pdev->dev, "Invalid or missing channel\n");
0326         return -EINVAL;
0327     }
0328 
0329     /* Register channels and initialize clocks */
0330     for (i = 0; i < priv->num_channels; i++) {
0331         ret = of_property_read_u32_index(np, "reg", i, &channel);
0332         if (ret < 0 || channel > 2)
0333             return -ENODEV;
0334 
0335         priv->channel[i] = channel;
0336 
0337         snprintf(clk_name, sizeof(clk_name), "t%d_clk", channel);
0338 
0339         clk[i] = of_clk_get_by_name(np->parent, clk_name);
0340         if (IS_ERR(clk[i])) {
0341             /* Fallback to t0_clk */
0342             clk[i] = of_clk_get_by_name(np->parent, "t0_clk");
0343             if (IS_ERR(clk[i]))
0344                 return PTR_ERR(clk[i]);
0345         }
0346 
0347         ret = clk_prepare_enable(clk[i]);
0348         if (ret)
0349             return ret;
0350 
0351         ret = devm_add_action_or_reset(&pdev->dev,
0352                            mchp_tc_clk_remove,
0353                            clk[i]);
0354         if (ret)
0355             return ret;
0356 
0357         dev_dbg(&pdev->dev,
0358             "Initialized capture mode on channel %d\n",
0359             channel);
0360     }
0361 
0362     priv->tc_cfg = tcb_config;
0363     priv->regmap = regmap;
0364     counter->name = dev_name(&pdev->dev);
0365     counter->parent = &pdev->dev;
0366     counter->ops = &mchp_tc_ops;
0367     counter->num_counts = ARRAY_SIZE(mchp_tc_counts);
0368     counter->counts = mchp_tc_counts;
0369     counter->num_signals = ARRAY_SIZE(mchp_tc_count_signals);
0370     counter->signals = mchp_tc_count_signals;
0371 
0372     ret = devm_counter_add(&pdev->dev, counter);
0373     if (ret < 0)
0374         return dev_err_probe(&pdev->dev, ret, "Failed to add counter\n");
0375 
0376     return 0;
0377 }
0378 
0379 static const struct of_device_id mchp_tc_dt_ids[] = {
0380     { .compatible = "microchip,tcb-capture", },
0381     { /* sentinel */ },
0382 };
0383 MODULE_DEVICE_TABLE(of, mchp_tc_dt_ids);
0384 
0385 static struct platform_driver mchp_tc_driver = {
0386     .probe = mchp_tc_probe,
0387     .driver = {
0388         .name = "microchip-tcb-capture",
0389         .of_match_table = mchp_tc_dt_ids,
0390     },
0391 };
0392 module_platform_driver(mchp_tc_driver);
0393 
0394 MODULE_AUTHOR("Kamel Bouhara <kamel.bouhara@bootlin.com>");
0395 MODULE_DESCRIPTION("Microchip TCB Capture driver");
0396 MODULE_LICENSE("GPL v2");