aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris BREZILLON <b.brezillon@overkiz.com>2013-10-11 06:22:06 -0400
committerNicolas Ferre <nicolas.ferre@atmel.com>2013-12-02 09:31:25 -0500
commitf090fb37def3eb9ea49b71751dbe43f423f3a152 (patch)
tree50cb4902013dfa7addaeaba993b37f8af674303b
parent1f22f8bb64b3619324020b48b03181914b1f5544 (diff)
clk: at91: add PMC utmi clock
This adds new at91 utmi clock implementation using common clk framework. This clock is a pll with a fixed factor (x40). It is used as a source for usb clock. Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com> Acked-by: Mike Turquette <mturquette@linaro.org> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-rw-r--r--arch/arm/mach-at91/Kconfig7
-rw-r--r--drivers/clk/at91/Makefile1
-rw-r--r--drivers/clk/at91/clk-utmi.c159
-rw-r--r--drivers/clk/at91/pmc.c7
-rw-r--r--drivers/clk/at91/pmc.h5
5 files changed, 179 insertions, 0 deletions
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 85b53a441459..6ad37daca971 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -1,5 +1,8 @@
1if ARCH_AT91 1if ARCH_AT91
2 2
3config HAVE_AT91_UTMI
4 bool
5
3config HAVE_AT91_DBGU0 6config HAVE_AT91_DBGU0
4 bool 7 bool
5 8
@@ -78,6 +81,7 @@ config SOC_SAMA5D3
78 select HAVE_FB_ATMEL 81 select HAVE_FB_ATMEL
79 select HAVE_AT91_DBGU1 82 select HAVE_AT91_DBGU1
80 select AT91_USE_OLD_CLK 83 select AT91_USE_OLD_CLK
84 select HAVE_AT91_UTMI
81 help 85 help
82 Select this if you are using one of Atmel's SAMA5D3 family SoC. 86 Select this if you are using one of Atmel's SAMA5D3 family SoC.
83 This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35. 87 This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35.
@@ -124,6 +128,7 @@ config SOC_AT91SAM9RL
124 select HAVE_FB_ATMEL 128 select HAVE_FB_ATMEL
125 select SOC_AT91SAM9 129 select SOC_AT91SAM9
126 select AT91_USE_OLD_CLK 130 select AT91_USE_OLD_CLK
131 select HAVE_AT91_UTMI
127 132
128config SOC_AT91SAM9G45 133config SOC_AT91SAM9G45
129 bool "AT91SAM9G45 or AT91SAM9M10 families" 134 bool "AT91SAM9G45 or AT91SAM9M10 families"
@@ -131,6 +136,7 @@ config SOC_AT91SAM9G45
131 select HAVE_FB_ATMEL 136 select HAVE_FB_ATMEL
132 select SOC_AT91SAM9 137 select SOC_AT91SAM9
133 select AT91_USE_OLD_CLK 138 select AT91_USE_OLD_CLK
139 select HAVE_AT91_UTMI
134 help 140 help
135 Select this if you are using one of Atmel's AT91SAM9G45 family SoC. 141 Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
136 This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11. 142 This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
@@ -141,6 +147,7 @@ config SOC_AT91SAM9X5
141 select HAVE_FB_ATMEL 147 select HAVE_FB_ATMEL
142 select SOC_AT91SAM9 148 select SOC_AT91SAM9
143 select AT91_USE_OLD_CLK 149 select AT91_USE_OLD_CLK
150 select HAVE_AT91_UTMI
144 help 151 help
145 Select this if you are using one of Atmel's AT91SAM9x5 family SoC. 152 Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
146 This means that your SAM9 name finishes with a '5' (except if it is 153 This means that your SAM9 name finishes with a '5' (except if it is
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 3873b621768f..a82488323ea4 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -7,3 +7,4 @@ obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
7obj-y += clk-system.o clk-peripheral.o 7obj-y += clk-system.o clk-peripheral.o
8 8
9obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS) += clk-programmable.o 9obj-$(CONFIG_AT91_PROGRAMMABLE_CLOCKS) += clk-programmable.o
10obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
new file mode 100644
index 000000000000..ae3263bc1476
--- /dev/null
+++ b/drivers/clk/at91/clk-utmi.c
@@ -0,0 +1,159 @@
1/*
2 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 */
10
11#include <linux/clk-provider.h>
12#include <linux/clkdev.h>
13#include <linux/clk/at91_pmc.h>
14#include <linux/interrupt.h>
15#include <linux/irq.h>
16#include <linux/of.h>
17#include <linux/of_address.h>
18#include <linux/of_irq.h>
19#include <linux/io.h>
20#include <linux/sched.h>
21#include <linux/wait.h>
22
23#include "pmc.h"
24
25#define UTMI_FIXED_MUL 40
26
27struct clk_utmi {
28 struct clk_hw hw;
29 struct at91_pmc *pmc;
30 unsigned int irq;
31 wait_queue_head_t wait;
32};
33
34#define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw)
35
36static irqreturn_t clk_utmi_irq_handler(int irq, void *dev_id)
37{
38 struct clk_utmi *utmi = (struct clk_utmi *)dev_id;
39
40 wake_up(&utmi->wait);
41 disable_irq_nosync(utmi->irq);
42
43 return IRQ_HANDLED;
44}
45
46static int clk_utmi_prepare(struct clk_hw *hw)
47{
48 struct clk_utmi *utmi = to_clk_utmi(hw);
49 struct at91_pmc *pmc = utmi->pmc;
50 u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) | AT91_PMC_UPLLEN |
51 AT91_PMC_UPLLCOUNT | AT91_PMC_BIASEN;
52
53 pmc_write(pmc, AT91_CKGR_UCKR, tmp);
54
55 while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU)) {
56 enable_irq(utmi->irq);
57 wait_event(utmi->wait,
58 pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
59 }
60
61 return 0;
62}
63
64static int clk_utmi_is_prepared(struct clk_hw *hw)
65{
66 struct clk_utmi *utmi = to_clk_utmi(hw);
67 struct at91_pmc *pmc = utmi->pmc;
68
69 return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
70}
71
72static void clk_utmi_unprepare(struct clk_hw *hw)
73{
74 struct clk_utmi *utmi = to_clk_utmi(hw);
75 struct at91_pmc *pmc = utmi->pmc;
76 u32 tmp = at91_pmc_read(AT91_CKGR_UCKR) & ~AT91_PMC_UPLLEN;
77
78 pmc_write(pmc, AT91_CKGR_UCKR, tmp);
79}
80
81static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw,
82 unsigned long parent_rate)
83{
84 /* UTMI clk is a fixed clk multiplier */
85 return parent_rate * UTMI_FIXED_MUL;
86}
87
88static const struct clk_ops utmi_ops = {
89 .prepare = clk_utmi_prepare,
90 .unprepare = clk_utmi_unprepare,
91 .is_prepared = clk_utmi_is_prepared,
92 .recalc_rate = clk_utmi_recalc_rate,
93};
94
95static struct clk * __init
96at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq,
97 const char *name, const char *parent_name)
98{
99 int ret;
100 struct clk_utmi *utmi;
101 struct clk *clk = NULL;
102 struct clk_init_data init;
103
104 utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
105 if (!utmi)
106 return ERR_PTR(-ENOMEM);
107
108 init.name = name;
109 init.ops = &utmi_ops;
110 init.parent_names = parent_name ? &parent_name : NULL;
111 init.num_parents = parent_name ? 1 : 0;
112 init.flags = CLK_SET_RATE_GATE;
113
114 utmi->hw.init = &init;
115 utmi->pmc = pmc;
116 utmi->irq = irq;
117 init_waitqueue_head(&utmi->wait);
118 irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
119 ret = request_irq(utmi->irq, clk_utmi_irq_handler,
120 IRQF_TRIGGER_HIGH, "clk-utmi", utmi);
121 if (ret)
122 return ERR_PTR(ret);
123
124 clk = clk_register(NULL, &utmi->hw);
125 if (IS_ERR(clk))
126 kfree(utmi);
127
128 return clk;
129}