root/drivers/clk/clk-max77686.c

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

DEFINITIONS

This source file includes following definitions.
  1. to_max77686_clk_init_data
  2. max77686_clk_prepare
  3. max77686_clk_unprepare
  4. max77686_clk_is_prepared
  5. max77686_recalc_rate
  6. of_clk_max77686_get
  7. max77686_clk_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 //
   3 // clk-max77686.c - Clock driver for Maxim 77686/MAX77802
   4 //
   5 // Copyright (C) 2012 Samsung Electornics
   6 // Jonghwa Lee <jonghwa3.lee@samsung.com>
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/slab.h>
  10 #include <linux/err.h>
  11 #include <linux/module.h>
  12 #include <linux/platform_device.h>
  13 #include <linux/mfd/max77620.h>
  14 #include <linux/mfd/max77686.h>
  15 #include <linux/mfd/max77686-private.h>
  16 #include <linux/clk-provider.h>
  17 #include <linux/mutex.h>
  18 #include <linux/clkdev.h>
  19 #include <linux/of.h>
  20 #include <linux/regmap.h>
  21 
  22 #include <dt-bindings/clock/maxim,max77686.h>
  23 #include <dt-bindings/clock/maxim,max77802.h>
  24 #include <dt-bindings/clock/maxim,max77620.h>
  25 
  26 #define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3
  27 
  28 enum max77686_chip_name {
  29         CHIP_MAX77686,
  30         CHIP_MAX77802,
  31         CHIP_MAX77620,
  32 };
  33 
  34 struct max77686_hw_clk_info {
  35         const char *name;
  36         u32 clk_reg;
  37         u32 clk_enable_mask;
  38         u32 flags;
  39 };
  40 
  41 struct max77686_clk_init_data {
  42         struct regmap *regmap;
  43         struct clk_hw hw;
  44         struct clk_init_data clk_idata;
  45         const struct max77686_hw_clk_info *clk_info;
  46 };
  47 
  48 struct max77686_clk_driver_data {
  49         enum max77686_chip_name chip;
  50         struct max77686_clk_init_data *max_clk_data;
  51         size_t num_clks;
  52 };
  53 
  54 static const struct
  55 max77686_hw_clk_info max77686_hw_clks_info[MAX77686_CLKS_NUM] = {
  56         [MAX77686_CLK_AP] = {
  57                 .name = "32khz_ap",
  58                 .clk_reg = MAX77686_REG_32KHZ,
  59                 .clk_enable_mask = BIT(MAX77686_CLK_AP),
  60         },
  61         [MAX77686_CLK_CP] = {
  62                 .name = "32khz_cp",
  63                 .clk_reg = MAX77686_REG_32KHZ,
  64                 .clk_enable_mask = BIT(MAX77686_CLK_CP),
  65         },
  66         [MAX77686_CLK_PMIC] = {
  67                 .name = "32khz_pmic",
  68                 .clk_reg = MAX77686_REG_32KHZ,
  69                 .clk_enable_mask = BIT(MAX77686_CLK_PMIC),
  70         },
  71 };
  72 
  73 static const struct
  74 max77686_hw_clk_info max77802_hw_clks_info[MAX77802_CLKS_NUM] = {
  75         [MAX77802_CLK_32K_AP] = {
  76                 .name = "32khz_ap",
  77                 .clk_reg = MAX77802_REG_32KHZ,
  78                 .clk_enable_mask = BIT(MAX77802_CLK_32K_AP),
  79         },
  80         [MAX77802_CLK_32K_CP] = {
  81                 .name = "32khz_cp",
  82                 .clk_reg = MAX77802_REG_32KHZ,
  83                 .clk_enable_mask = BIT(MAX77802_CLK_32K_CP),
  84         },
  85 };
  86 
  87 static const struct
  88 max77686_hw_clk_info max77620_hw_clks_info[MAX77620_CLKS_NUM] = {
  89         [MAX77620_CLK_32K_OUT0] = {
  90                 .name = "32khz_out0",
  91                 .clk_reg = MAX77620_REG_CNFG1_32K,
  92                 .clk_enable_mask = MAX77620_CNFG1_32K_OUT0_EN,
  93         },
  94 };
  95 
  96 static struct max77686_clk_init_data *to_max77686_clk_init_data(
  97                                 struct clk_hw *hw)
  98 {
  99         return container_of(hw, struct max77686_clk_init_data, hw);
 100 }
 101 
 102 static int max77686_clk_prepare(struct clk_hw *hw)
 103 {
 104         struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw);
 105 
 106         return regmap_update_bits(max77686->regmap, max77686->clk_info->clk_reg,
 107                                   max77686->clk_info->clk_enable_mask,
 108                                   max77686->clk_info->clk_enable_mask);
 109 }
 110 
 111 static void max77686_clk_unprepare(struct clk_hw *hw)
 112 {
 113         struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw);
 114 
 115         regmap_update_bits(max77686->regmap, max77686->clk_info->clk_reg,
 116                            max77686->clk_info->clk_enable_mask,
 117                            ~max77686->clk_info->clk_enable_mask);
 118 }
 119 
 120 static int max77686_clk_is_prepared(struct clk_hw *hw)
 121 {
 122         struct max77686_clk_init_data *max77686 = to_max77686_clk_init_data(hw);
 123         int ret;
 124         u32 val;
 125 
 126         ret = regmap_read(max77686->regmap, max77686->clk_info->clk_reg, &val);
 127 
 128         if (ret < 0)
 129                 return -EINVAL;
 130 
 131         return val & max77686->clk_info->clk_enable_mask;
 132 }
 133 
 134 static unsigned long max77686_recalc_rate(struct clk_hw *hw,
 135                                           unsigned long parent_rate)
 136 {
 137         return 32768;
 138 }
 139 
 140 static const struct clk_ops max77686_clk_ops = {
 141         .prepare        = max77686_clk_prepare,
 142         .unprepare      = max77686_clk_unprepare,
 143         .is_prepared    = max77686_clk_is_prepared,
 144         .recalc_rate    = max77686_recalc_rate,
 145 };
 146 
 147 static struct clk_hw *
 148 of_clk_max77686_get(struct of_phandle_args *clkspec, void *data)
 149 {
 150         struct max77686_clk_driver_data *drv_data = data;
 151         unsigned int idx = clkspec->args[0];
 152 
 153         if (idx >= drv_data->num_clks) {
 154                 pr_err("%s: invalid index %u\n", __func__, idx);
 155                 return ERR_PTR(-EINVAL);
 156         }
 157 
 158         return &drv_data->max_clk_data[idx].hw;
 159 }
 160 
 161 static int max77686_clk_probe(struct platform_device *pdev)
 162 {
 163         struct device *dev = &pdev->dev;
 164         struct device *parent = dev->parent;
 165         const struct platform_device_id *id = platform_get_device_id(pdev);
 166         struct max77686_clk_driver_data *drv_data;
 167         const struct max77686_hw_clk_info *hw_clks;
 168         struct regmap *regmap;
 169         int i, ret, num_clks;
 170 
 171         drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
 172         if (!drv_data)
 173                 return -ENOMEM;
 174 
 175         regmap = dev_get_regmap(parent, NULL);
 176         if (!regmap) {
 177                 dev_err(dev, "Failed to get rtc regmap\n");
 178                 return -ENODEV;
 179         }
 180 
 181         drv_data->chip = id->driver_data;
 182 
 183         switch (drv_data->chip) {
 184         case CHIP_MAX77686:
 185                 num_clks = MAX77686_CLKS_NUM;
 186                 hw_clks = max77686_hw_clks_info;
 187                 break;
 188 
 189         case CHIP_MAX77802:
 190                 num_clks = MAX77802_CLKS_NUM;
 191                 hw_clks = max77802_hw_clks_info;
 192                 break;
 193 
 194         case CHIP_MAX77620:
 195                 num_clks = MAX77620_CLKS_NUM;
 196                 hw_clks = max77620_hw_clks_info;
 197                 break;
 198 
 199         default:
 200                 dev_err(dev, "Unknown Chip ID\n");
 201                 return -EINVAL;
 202         }
 203 
 204         drv_data->num_clks = num_clks;
 205         drv_data->max_clk_data = devm_kcalloc(dev, num_clks,
 206                                               sizeof(*drv_data->max_clk_data),
 207                                               GFP_KERNEL);
 208         if (!drv_data->max_clk_data)
 209                 return -ENOMEM;
 210 
 211         for (i = 0; i < num_clks; i++) {
 212                 struct max77686_clk_init_data *max_clk_data;
 213                 const char *clk_name;
 214 
 215                 max_clk_data = &drv_data->max_clk_data[i];
 216 
 217                 max_clk_data->regmap = regmap;
 218                 max_clk_data->clk_info = &hw_clks[i];
 219                 max_clk_data->clk_idata.flags = hw_clks[i].flags;
 220                 max_clk_data->clk_idata.ops = &max77686_clk_ops;
 221 
 222                 if (parent->of_node &&
 223                     !of_property_read_string_index(parent->of_node,
 224                                                    "clock-output-names",
 225                                                    i, &clk_name))
 226                         max_clk_data->clk_idata.name = clk_name;
 227                 else
 228                         max_clk_data->clk_idata.name = hw_clks[i].name;
 229 
 230                 max_clk_data->hw.init = &max_clk_data->clk_idata;
 231 
 232                 ret = devm_clk_hw_register(dev, &max_clk_data->hw);
 233                 if (ret) {
 234                         dev_err(dev, "Failed to clock register: %d\n", ret);
 235                         return ret;
 236                 }
 237 
 238                 ret = devm_clk_hw_register_clkdev(dev, &max_clk_data->hw,
 239                                                   max_clk_data->clk_idata.name,
 240                                                   NULL);
 241                 if (ret < 0) {
 242                         dev_err(dev, "Failed to clkdev register: %d\n", ret);
 243                         return ret;
 244                 }
 245         }
 246 
 247         if (parent->of_node) {
 248                 ret = devm_of_clk_add_hw_provider(dev, of_clk_max77686_get,
 249                                                   drv_data);
 250 
 251                 if (ret < 0) {
 252                         dev_err(dev, "Failed to register OF clock provider: %d\n",
 253                                 ret);
 254                         return ret;
 255                 }
 256         }
 257 
 258         /* MAX77802: Enable low-jitter mode on the 32khz clocks. */
 259         if (drv_data->chip == CHIP_MAX77802) {
 260                 ret = regmap_update_bits(regmap, MAX77802_REG_32KHZ,
 261                                          1 << MAX77802_CLOCK_LOW_JITTER_SHIFT,
 262                                          1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
 263                 if (ret < 0) {
 264                         dev_err(dev, "Failed to config low-jitter: %d\n", ret);
 265                         return ret;
 266                 }
 267         }
 268 
 269         return 0;
 270 }
 271 
 272 static const struct platform_device_id max77686_clk_id[] = {
 273         { "max77686-clk", .driver_data = CHIP_MAX77686, },
 274         { "max77802-clk", .driver_data = CHIP_MAX77802, },
 275         { "max77620-clock", .driver_data = CHIP_MAX77620, },
 276         {},
 277 };
 278 MODULE_DEVICE_TABLE(platform, max77686_clk_id);
 279 
 280 static struct platform_driver max77686_clk_driver = {
 281         .driver = {
 282                 .name  = "max77686-clk",
 283         },
 284         .probe = max77686_clk_probe,
 285         .id_table = max77686_clk_id,
 286 };
 287 
 288 module_platform_driver(max77686_clk_driver);
 289 
 290 MODULE_DESCRIPTION("MAXIM 77686 Clock Driver");
 291 MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>");
 292 MODULE_LICENSE("GPL");

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