linux/drivers/clk/clk-max77686.c
<<
>>
Prefs
   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
  28enum max77686_chip_name {
  29        CHIP_MAX77686,
  30        CHIP_MAX77802,
  31        CHIP_MAX77620,
  32};
  33
  34struct max77686_hw_clk_info {
  35        const char *name;
  36        u32 clk_reg;
  37        u32 clk_enable_mask;
  38        u32 flags;
  39};
  40
  41struct 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
  48struct 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
  54static const struct
  55max77686_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
  73static const struct
  74max77686_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
  87static const struct
  88max77686_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
  96static 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
 102static 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
 111static 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
 120static 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
 134static unsigned long max77686_recalc_rate(struct clk_hw *hw,
 135                                          unsigned long parent_rate)
 136{
 137        return 32768;
 138}
 139
 140static 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
 147static struct clk_hw *
 148of_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
 161static 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 = clk_hw_register_clkdev(&max_clk_data->hw,
 239                                             max_clk_data->clk_idata.name, NULL);
 240                if (ret < 0) {
 241                        dev_err(dev, "Failed to clkdev register: %d\n", ret);
 242                        return ret;
 243                }
 244        }
 245
 246        if (parent->of_node) {
 247                ret = of_clk_add_hw_provider(parent->of_node, of_clk_max77686_get,
 248                                             drv_data);
 249
 250                if (ret < 0) {
 251                        dev_err(dev, "Failed to register OF clock provider: %d\n",
 252                                ret);
 253                        return ret;
 254                }
 255        }
 256
 257        /* MAX77802: Enable low-jitter mode on the 32khz clocks. */
 258        if (drv_data->chip == CHIP_MAX77802) {
 259                ret = regmap_update_bits(regmap, MAX77802_REG_32KHZ,
 260                                         1 << MAX77802_CLOCK_LOW_JITTER_SHIFT,
 261                                         1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
 262                if (ret < 0) {
 263                        dev_err(dev, "Failed to config low-jitter: %d\n", ret);
 264                        goto remove_of_clk_provider;
 265                }
 266        }
 267
 268        return 0;
 269
 270remove_of_clk_provider:
 271        if (parent->of_node)
 272                of_clk_del_provider(parent->of_node);
 273
 274        return ret;
 275}
 276
 277static int max77686_clk_remove(struct platform_device *pdev)
 278{
 279        struct device *parent = pdev->dev.parent;
 280
 281        if (parent->of_node)
 282                of_clk_del_provider(parent->of_node);
 283
 284        return 0;
 285}
 286
 287static const struct platform_device_id max77686_clk_id[] = {
 288        { "max77686-clk", .driver_data = CHIP_MAX77686, },
 289        { "max77802-clk", .driver_data = CHIP_MAX77802, },
 290        { "max77620-clock", .driver_data = CHIP_MAX77620, },
 291        {},
 292};
 293MODULE_DEVICE_TABLE(platform, max77686_clk_id);
 294
 295static struct platform_driver max77686_clk_driver = {
 296        .driver = {
 297                .name  = "max77686-clk",
 298        },
 299        .probe = max77686_clk_probe,
 300        .remove = max77686_clk_remove,
 301        .id_table = max77686_clk_id,
 302};
 303
 304module_platform_driver(max77686_clk_driver);
 305
 306MODULE_DESCRIPTION("MAXIM 77686 Clock Driver");
 307MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>");
 308MODULE_LICENSE("GPL");
 309