root/drivers/clk/sunxi/clk-sun9i-mmc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sun9i_mmc_reset_assert
  2. sun9i_mmc_reset_deassert
  3. sun9i_mmc_reset_reset
  4. sun9i_a80_mmc_config_clk_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright 2015 Chen-Yu Tsai
   4  *
   5  * Chen-Yu Tsai <wens@csie.org>
   6  */
   7 
   8 #include <linux/clk.h>
   9 #include <linux/clk-provider.h>
  10 #include <linux/delay.h>
  11 #include <linux/init.h>
  12 #include <linux/io.h>
  13 #include <linux/of.h>
  14 #include <linux/of_device.h>
  15 #include <linux/reset.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/reset-controller.h>
  18 #include <linux/slab.h>
  19 #include <linux/spinlock.h>
  20 
  21 #define SUN9I_MMC_WIDTH         4
  22 
  23 #define SUN9I_MMC_GATE_BIT      16
  24 #define SUN9I_MMC_RESET_BIT     18
  25 
  26 struct sun9i_mmc_clk_data {
  27         spinlock_t                      lock;
  28         void __iomem                    *membase;
  29         struct clk                      *clk;
  30         struct reset_control            *reset;
  31         struct clk_onecell_data         clk_data;
  32         struct reset_controller_dev     rcdev;
  33 };
  34 
  35 static int sun9i_mmc_reset_assert(struct reset_controller_dev *rcdev,
  36                               unsigned long id)
  37 {
  38         struct sun9i_mmc_clk_data *data = container_of(rcdev,
  39                                                        struct sun9i_mmc_clk_data,
  40                                                        rcdev);
  41         unsigned long flags;
  42         void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
  43         u32 val;
  44 
  45         clk_prepare_enable(data->clk);
  46         spin_lock_irqsave(&data->lock, flags);
  47 
  48         val = readl(reg);
  49         writel(val & ~BIT(SUN9I_MMC_RESET_BIT), reg);
  50 
  51         spin_unlock_irqrestore(&data->lock, flags);
  52         clk_disable_unprepare(data->clk);
  53 
  54         return 0;
  55 }
  56 
  57 static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev,
  58                                 unsigned long id)
  59 {
  60         struct sun9i_mmc_clk_data *data = container_of(rcdev,
  61                                                        struct sun9i_mmc_clk_data,
  62                                                        rcdev);
  63         unsigned long flags;
  64         void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
  65         u32 val;
  66 
  67         clk_prepare_enable(data->clk);
  68         spin_lock_irqsave(&data->lock, flags);
  69 
  70         val = readl(reg);
  71         writel(val | BIT(SUN9I_MMC_RESET_BIT), reg);
  72 
  73         spin_unlock_irqrestore(&data->lock, flags);
  74         clk_disable_unprepare(data->clk);
  75 
  76         return 0;
  77 }
  78 
  79 static int sun9i_mmc_reset_reset(struct reset_controller_dev *rcdev,
  80                                  unsigned long id)
  81 {
  82         sun9i_mmc_reset_assert(rcdev, id);
  83         udelay(10);
  84         sun9i_mmc_reset_deassert(rcdev, id);
  85 
  86         return 0;
  87 }
  88 
  89 static const struct reset_control_ops sun9i_mmc_reset_ops = {
  90         .assert         = sun9i_mmc_reset_assert,
  91         .deassert       = sun9i_mmc_reset_deassert,
  92         .reset          = sun9i_mmc_reset_reset,
  93 };
  94 
  95 static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev)
  96 {
  97         struct device_node *np = pdev->dev.of_node;
  98         struct sun9i_mmc_clk_data *data;
  99         struct clk_onecell_data *clk_data;
 100         const char *clk_name = np->name;
 101         const char *clk_parent;
 102         struct resource *r;
 103         int count, i, ret;
 104 
 105         data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 106         if (!data)
 107                 return -ENOMEM;
 108 
 109         spin_lock_init(&data->lock);
 110 
 111         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 112         /* one clock/reset pair per word */
 113         count = DIV_ROUND_UP((resource_size(r)), SUN9I_MMC_WIDTH);
 114         data->membase = devm_ioremap_resource(&pdev->dev, r);
 115         if (IS_ERR(data->membase))
 116                 return PTR_ERR(data->membase);
 117 
 118         clk_data = &data->clk_data;
 119         clk_data->clk_num = count;
 120         clk_data->clks = devm_kcalloc(&pdev->dev, count, sizeof(struct clk *),
 121                                       GFP_KERNEL);
 122         if (!clk_data->clks)
 123                 return -ENOMEM;
 124 
 125         data->clk = devm_clk_get(&pdev->dev, NULL);
 126         if (IS_ERR(data->clk)) {
 127                 dev_err(&pdev->dev, "Could not get clock\n");
 128                 return PTR_ERR(data->clk);
 129         }
 130 
 131         data->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 132         if (IS_ERR(data->reset)) {
 133                 dev_err(&pdev->dev, "Could not get reset control\n");
 134                 return PTR_ERR(data->reset);
 135         }
 136 
 137         ret = reset_control_deassert(data->reset);
 138         if (ret) {
 139                 dev_err(&pdev->dev, "Reset deassert err %d\n", ret);
 140                 return ret;
 141         }
 142 
 143         clk_parent = __clk_get_name(data->clk);
 144         for (i = 0; i < count; i++) {
 145                 of_property_read_string_index(np, "clock-output-names",
 146                                               i, &clk_name);
 147 
 148                 clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
 149                                                       clk_parent, 0,
 150                                                       data->membase + SUN9I_MMC_WIDTH * i,
 151                                                       SUN9I_MMC_GATE_BIT, 0,
 152                                                       &data->lock);
 153 
 154                 if (IS_ERR(clk_data->clks[i])) {
 155                         ret = PTR_ERR(clk_data->clks[i]);
 156                         goto err_clk_register;
 157                 }
 158         }
 159 
 160         ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
 161         if (ret)
 162                 goto err_clk_provider;
 163 
 164         data->rcdev.owner = THIS_MODULE;
 165         data->rcdev.nr_resets = count;
 166         data->rcdev.ops = &sun9i_mmc_reset_ops;
 167         data->rcdev.of_node = pdev->dev.of_node;
 168 
 169         ret = reset_controller_register(&data->rcdev);
 170         if (ret)
 171                 goto err_rc_reg;
 172 
 173         platform_set_drvdata(pdev, data);
 174 
 175         return 0;
 176 
 177 err_rc_reg:
 178         of_clk_del_provider(np);
 179 
 180 err_clk_provider:
 181         for (i = 0; i < count; i++)
 182                 clk_unregister(clk_data->clks[i]);
 183 
 184 err_clk_register:
 185         reset_control_assert(data->reset);
 186 
 187         return ret;
 188 }
 189 
 190 static const struct of_device_id sun9i_a80_mmc_config_clk_dt_ids[] = {
 191         { .compatible = "allwinner,sun9i-a80-mmc-config-clk" },
 192         { /* sentinel */ }
 193 };
 194 
 195 static struct platform_driver sun9i_a80_mmc_config_clk_driver = {
 196         .driver = {
 197                 .name = "sun9i-a80-mmc-config-clk",
 198                 .suppress_bind_attrs = true,
 199                 .of_match_table = sun9i_a80_mmc_config_clk_dt_ids,
 200         },
 201         .probe = sun9i_a80_mmc_config_clk_probe,
 202 };
 203 builtin_platform_driver(sun9i_a80_mmc_config_clk_driver);

/* [<][>][^][v][top][bottom][index][help] */