linux/drivers/clk/clk-twl6040.c
<<
>>
Prefs
   1/*
   2* TWL6040 clock module driver for OMAP4 McPDM functional clock
   3*
   4* Copyright (C) 2012 Texas Instruments Inc.
   5* Peter Ujfalusi <peter.ujfalusi@ti.com>
   6*
   7* This program is free software; you can redistribute it and/or
   8* modify it under the terms of the GNU General Public License
   9* version 2 as published by the Free Software Foundation.
  10*
  11* This program is distributed in the hope that it will be useful, but
  12* WITHOUT ANY WARRANTY; without even the implied warranty of
  13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14* General Public License for more details.
  15*
  16* You should have received a copy of the GNU General Public License
  17* along with this program; if not, write to the Free Software
  18* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  19* 02110-1301 USA
  20*
  21*/
  22
  23#include <linux/module.h>
  24#include <linux/slab.h>
  25#include <linux/platform_device.h>
  26#include <linux/mfd/twl6040.h>
  27#include <linux/clk-provider.h>
  28
  29struct twl6040_pdmclk {
  30        struct twl6040 *twl6040;
  31        struct device *dev;
  32        struct clk_hw pdmclk_hw;
  33        int enabled;
  34};
  35
  36static int twl6040_pdmclk_is_prepared(struct clk_hw *hw)
  37{
  38        struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
  39                                                     pdmclk_hw);
  40
  41        return pdmclk->enabled;
  42}
  43
  44static int twl6040_pdmclk_prepare(struct clk_hw *hw)
  45{
  46        struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
  47                                                     pdmclk_hw);
  48        int ret;
  49
  50        ret = twl6040_power(pdmclk->twl6040, 1);
  51        if (!ret)
  52                pdmclk->enabled = 1;
  53
  54        return ret;
  55}
  56
  57static void twl6040_pdmclk_unprepare(struct clk_hw *hw)
  58{
  59        struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
  60                                                     pdmclk_hw);
  61        int ret;
  62
  63        ret = twl6040_power(pdmclk->twl6040, 0);
  64        if (!ret)
  65                pdmclk->enabled = 0;
  66
  67}
  68
  69static unsigned long twl6040_pdmclk_recalc_rate(struct clk_hw *hw,
  70                                                unsigned long parent_rate)
  71{
  72        struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
  73                                                     pdmclk_hw);
  74
  75        return twl6040_get_sysclk(pdmclk->twl6040);
  76}
  77
  78static const struct clk_ops twl6040_pdmclk_ops = {
  79        .is_prepared = twl6040_pdmclk_is_prepared,
  80        .prepare = twl6040_pdmclk_prepare,
  81        .unprepare = twl6040_pdmclk_unprepare,
  82        .recalc_rate = twl6040_pdmclk_recalc_rate,
  83};
  84
  85static struct clk_init_data twl6040_pdmclk_init = {
  86        .name = "pdmclk",
  87        .ops = &twl6040_pdmclk_ops,
  88        .flags = CLK_GET_RATE_NOCACHE,
  89};
  90
  91static int twl6040_pdmclk_probe(struct platform_device *pdev)
  92{
  93        struct twl6040 *twl6040 = dev_get_drvdata(pdev->dev.parent);
  94        struct twl6040_pdmclk *clkdata;
  95        int ret;
  96
  97        clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL);
  98        if (!clkdata)
  99                return -ENOMEM;
 100
 101        clkdata->dev = &pdev->dev;
 102        clkdata->twl6040 = twl6040;
 103
 104        clkdata->pdmclk_hw.init = &twl6040_pdmclk_init;
 105        ret = devm_clk_hw_register(&pdev->dev, &clkdata->pdmclk_hw);
 106        if (ret)
 107                return ret;
 108
 109        platform_set_drvdata(pdev, clkdata);
 110
 111        return of_clk_add_hw_provider(pdev->dev.parent->of_node,
 112                                      of_clk_hw_simple_get,
 113                                      &clkdata->pdmclk_hw);
 114}
 115
 116static struct platform_driver twl6040_pdmclk_driver = {
 117        .driver = {
 118                .name = "twl6040-pdmclk",
 119        },
 120        .probe = twl6040_pdmclk_probe,
 121};
 122
 123module_platform_driver(twl6040_pdmclk_driver);
 124
 125MODULE_DESCRIPTION("TWL6040 clock driver for McPDM functional clock");
 126MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 127MODULE_ALIAS("platform:twl6040-pdmclk");
 128MODULE_LICENSE("GPL");
 129