linux/drivers/clk/at91/clk-usb.c
<<
>>
Prefs
   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/of.h>
  15#include <linux/of_address.h>
  16#include <linux/io.h>
  17
  18#include "pmc.h"
  19
  20#define USB_SOURCE_MAX          2
  21
  22#define SAM9X5_USB_DIV_SHIFT    8
  23#define SAM9X5_USB_MAX_DIV      0xf
  24
  25#define RM9200_USB_DIV_SHIFT    28
  26#define RM9200_USB_DIV_TAB_SIZE 4
  27
  28struct at91sam9x5_clk_usb {
  29        struct clk_hw hw;
  30        struct at91_pmc *pmc;
  31};
  32
  33#define to_at91sam9x5_clk_usb(hw) \
  34        container_of(hw, struct at91sam9x5_clk_usb, hw)
  35
  36struct at91rm9200_clk_usb {
  37        struct clk_hw hw;
  38        struct at91_pmc *pmc;
  39        u32 divisors[4];
  40};
  41
  42#define to_at91rm9200_clk_usb(hw) \
  43        container_of(hw, struct at91rm9200_clk_usb, hw)
  44
  45static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
  46                                                    unsigned long parent_rate)
  47{
  48        u32 tmp;
  49        u8 usbdiv;
  50        struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
  51        struct at91_pmc *pmc = usb->pmc;
  52
  53        tmp = pmc_read(pmc, AT91_PMC_USB);
  54        usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;
  55        return parent_rate / (usbdiv + 1);
  56}
  57
  58static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
  59                                          unsigned long *parent_rate)
  60{
  61        unsigned long div;
  62        unsigned long bestrate;
  63        unsigned long tmp;
  64
  65        if (rate >= *parent_rate)
  66                return *parent_rate;
  67
  68        div = *parent_rate / rate;
  69        if (div >= SAM9X5_USB_MAX_DIV)
  70                return *parent_rate / (SAM9X5_USB_MAX_DIV + 1);
  71
  72        bestrate = *parent_rate / div;
  73        tmp = *parent_rate / (div + 1);
  74        if (bestrate - rate > rate - tmp)
  75                bestrate = tmp;
  76
  77        return bestrate;
  78}
  79
  80static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
  81{
  82        u32 tmp;
  83        struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
  84        struct at91_pmc *pmc = usb->pmc;
  85
  86        if (index > 1)
  87                return -EINVAL;
  88        tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS;
  89        if (index)
  90                tmp |= AT91_PMC_USBS;
  91        pmc_write(pmc, AT91_PMC_USB, tmp);
  92        return 0;
  93}
  94
  95static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw)
  96{
  97        struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
  98        struct at91_pmc *pmc = usb->pmc;
  99
 100        return pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS;
 101}
 102
 103static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
 104                                       unsigned long parent_rate)
 105{
 106        u32 tmp;
 107        struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
 108        struct at91_pmc *pmc = usb->pmc;
 109        unsigned long div = parent_rate / rate;
 110
 111        if (parent_rate % rate || div < 1 || div >= SAM9X5_USB_MAX_DIV)
 112                return -EINVAL;
 113
 114        tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV;
 115        tmp |= (div - 1) << SAM9X5_USB_DIV_SHIFT;
 116        pmc_write(pmc, AT91_PMC_USB, tmp);
 117
 118        return 0;
 119}
 120
 121static const struct clk_ops at91sam9x5_usb_ops = {
 122        .recalc_rate = at91sam9x5_clk_usb_recalc_rate,
 123        .round_rate = at91sam9x5_clk_usb_round_rate,
 124        .get_parent = at91sam9x5_clk_usb_get_parent,
 125        .set_parent = at91sam9x5_clk_usb_set_parent,
 126        .set_rate = at91sam9x5_clk_usb_set_rate,
 127};
 128
 129static int at91sam9n12_clk_usb_enable(struct clk_hw *hw)
 130{
 131        struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
 132        struct at91_pmc *pmc = usb->pmc;
 133
 134        pmc_write(pmc, AT91_PMC_USB,
 135                  pmc_read(pmc, AT91_PMC_USB) | AT91_PMC_USBS);
 136        return 0;
 137}
 138
 139static void at91sam9n12_clk_usb_disable(struct clk_hw *hw)
 140{
 141        struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
 142        struct at91_pmc *pmc = usb->pmc;
 143
 144        pmc_write(pmc, AT91_PMC_USB,
 145                  pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS);
 146}
 147
 148static int at91sam9n12_clk_usb_is_enabled(struct clk_hw *hw)
 149{
 150        struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
 151        struct at91_pmc *pmc = usb->pmc;
 152
 153        return !!(pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS);
 154}
 155
 156static const struct clk_ops at91sam9n12_usb_ops = {
 157        .enable = at91sam9n12_clk_usb_enable,
 158        .disable = at91sam9n12_clk_usb_disable,
 159        .is_enabled = at91sam9n12_clk_usb_is_enabled,
 160        .recalc_rate = at91sam9x5_clk_usb_recalc_rate,
 161        .round_rate = at91sam9x5_clk_usb_round_rate,
 162        .set_rate = at91sam9x5_clk_usb_set_rate,
 163};
 164
 165static struct clk * __init
 166at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name,
 167                            const char **parent_names, u8 num_parents)
 168{
 169        struct at91sam9x5_clk_usb *usb;
 170        struct clk *clk = NULL;
 171        struct clk_init_data init;
 172
 173        usb = kzalloc(sizeof(*usb), GFP_KERNEL);
 174        if (!usb)
 175                return ERR_PTR(-ENOMEM);
 176
 177        init.name = name;
 178        init.ops = &at91sam9x5_usb_ops;
 179        init.parent_names = parent_names;
 180        init.num_parents = num_parents;
 181        init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
 182
 183        usb->hw.init = &init;
 184        usb->pmc = pmc;
 185
 186        clk = clk_register(NULL, &usb->hw);
 187        if (IS_ERR(clk))
 188                kfree(usb);
 189
 190        return clk;
 191}
 192
 193static struct clk * __init
 194at91sam9n12_clk_register_usb(struct at91_pmc *pmc, const char *name,
 195                             const char *parent_name)
 196{
 197        struct at91sam9x5_clk_usb *usb;
 198        struct clk *clk = NULL;
 199        struct clk_init_data init;
 200
 201        usb = kzalloc(sizeof(*usb), GFP_KERNEL);
 202        if (!usb)
 203                return ERR_PTR(-ENOMEM);
 204
 205        init.name = name;
 206        init.ops = &at91sam9n12_usb_ops;
 207        init.parent_names = &parent_name;
 208        init.num_parents = 1;
 209        init.flags = CLK_SET_RATE_GATE;
 210
 211        usb->hw.init = &init;
 212        usb->pmc = pmc;
 213
 214        clk = clk_register(NULL, &usb->hw);
 215        if (IS_ERR(clk))
 216                kfree(usb);
 217
 218        return clk;
 219}
 220
 221static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw,
 222                                                    unsigned long parent_rate)
 223{
 224        struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
 225        struct at91_pmc *pmc = usb->pmc;
 226        u32 tmp;
 227        u8 usbdiv;
 228
 229        tmp = pmc_read(pmc, AT91_CKGR_PLLBR);
 230        usbdiv = (tmp & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT;
 231        if (usb->divisors[usbdiv])
 232                return parent_rate / usb->divisors[usbdiv];
 233
 234        return 0;
 235}
 236
 237static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
 238                                          unsigned long *parent_rate)
 239{
 240        struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
 241        unsigned long bestrate = 0;
 242        int bestdiff = -1;
 243        unsigned long tmprate;
 244        int tmpdiff;
 245        int i = 0;
 246
 247        for (i = 0; i < 4; i++) {
 248                if (!usb->divisors[i])
 249                        continue;
 250                tmprate = *parent_rate / usb->divisors[i];
 251                if (tmprate < rate)
 252                        tmpdiff = rate - tmprate;
 253                else
 254                        tmpdiff = tmprate - rate;
 255
 256                if (bestdiff < 0 || bestdiff > tmpdiff) {
 257                        bestrate = tmprate;
 258                        bestdiff = tmpdiff;
 259                }
 260
 261                if (!bestdiff)
 262                        break;
 263        }
 264
 265        return bestrate;
 266}
 267
 268static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
 269                                       unsigned long parent_rate)
 270{
 271        u32 tmp;
 272        int i;
 273        struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
 274        struct at91_pmc *pmc = usb->pmc;
 275        unsigned long div = parent_rate / rate;
 276
 277        if (parent_rate % rate)
 278                return -EINVAL;
 279        for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
 280                if (usb->divisors[i] == div) {
 281                        tmp = pmc_read(pmc, AT91_CKGR_PLLBR) &
 282                              ~AT91_PMC_USBDIV;
 283                        tmp |= i << RM9200_USB_DIV_SHIFT;
 284                        pmc_write(pmc, AT91_CKGR_PLLBR, tmp);
 285                        return 0;
 286                }
 287        }
 288
 289        return -EINVAL;
 290}
 291
 292static const struct clk_ops at91rm9200_usb_ops = {
 293        .recalc_rate = at91rm9200_clk_usb_recalc_rate,
 294        .round_rate = at91rm9200_clk_usb_round_rate,
 295        .set_rate = at91rm9200_clk_usb_set_rate,
 296};
 297
 298static struct clk * __init
 299at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
 300                            const char *parent_name, const u32 *divisors)
 301{
 302        struct at91rm9200_clk_usb *usb;
 303        struct clk *clk = NULL;
 304        struct clk_init_data init;
 305
 306        usb = kzalloc(sizeof(*usb), GFP_KERNEL);
 307        if (!usb)
 308                return ERR_PTR(-ENOMEM);
 309
 310        init.name = name;
 311        init.ops = &at91rm9200_usb_ops;
 312        init.parent_names = &parent_name;
 313        init.num_parents = 1;
 314        init.flags = 0;
 315
 316        usb->hw.init = &init;
 317        usb->pmc = pmc;
 318        memcpy(usb->divisors, divisors, sizeof(usb->divisors));
 319
 320        clk = clk_register(NULL, &usb->hw);
 321        if (IS_ERR(clk))
 322                kfree(usb);
 323
 324        return clk;
 325}
 326
 327void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
 328                                        struct at91_pmc *pmc)
 329{
 330        struct clk *clk;
 331        int i;
 332        int num_parents;
 333        const char *parent_names[USB_SOURCE_MAX];
 334        const char *name = np->name;
 335
 336        num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
 337        if (num_parents <= 0 || num_parents > USB_SOURCE_MAX)
 338                return;
 339
 340        for (i = 0; i < num_parents; i++) {
 341                parent_names[i] = of_clk_get_parent_name(np, i);
 342                if (!parent_names[i])
 343                        return;
 344        }
 345
 346        of_property_read_string(np, "clock-output-names", &name);
 347
 348        clk = at91sam9x5_clk_register_usb(pmc, name, parent_names, num_parents);
 349        if (IS_ERR(clk))
 350                return;
 351
 352        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 353}
 354
 355void __init of_at91sam9n12_clk_usb_setup(struct device_node *np,
 356                                         struct at91_pmc *pmc)
 357{
 358        struct clk *clk;
 359        const char *parent_name;
 360        const char *name = np->name;
 361
 362        parent_name = of_clk_get_parent_name(np, 0);
 363        if (!parent_name)
 364                return;
 365
 366        of_property_read_string(np, "clock-output-names", &name);
 367
 368        clk = at91sam9n12_clk_register_usb(pmc, name, parent_name);
 369        if (IS_ERR(clk))
 370                return;
 371
 372        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 373}
 374
 375void __init of_at91rm9200_clk_usb_setup(struct device_node *np,
 376                                        struct at91_pmc *pmc)
 377{
 378        struct clk *clk;
 379        const char *parent_name;
 380        const char *name = np->name;
 381        u32 divisors[4] = {0, 0, 0, 0};
 382
 383        parent_name = of_clk_get_parent_name(np, 0);
 384        if (!parent_name)
 385                return;
 386
 387        of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4);
 388        if (!divisors[0])
 389                return;
 390
 391        of_property_read_string(np, "clock-output-names", &name);
 392
 393        clk = at91rm9200_clk_register_usb(pmc, name, parent_name, divisors);
 394        if (IS_ERR(clk))
 395                return;
 396
 397        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 398}
 399