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} 130 131static void __init 132of_at91_clk_utmi_setup(struct device_node *np, struct at91_pmc *pmc) 133{ 134 unsigned int irq; 135 struct clk *clk; 136 const char *parent_name; 137 const char *name = np->name; 138 139 parent_name = of_clk_get_parent_name(np, 0); 140 141 of_property_read_string(np, "clock-output-names", &name); 142 143 irq = irq_of_parse_and_map(np, 0); 144 if (!irq) 145 return; 146 147 clk = at91_clk_register_utmi(pmc, irq, name, parent_name); 148 if (IS_ERR(clk)) 149 return; 150 151 of_clk_add_provider(np, of_clk_src_simple_get, clk); 152 return; 153} 154 155void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np, 156 struct at91_pmc *pmc) 157{ 158 of_at91_clk_utmi_setup(np, pmc); 159} 160