Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
0004  */
0005 
0006 #include <linux/clk-provider.h>
0007 #include <linux/clkdev.h>
0008 #include <linux/clk/at91_pmc.h>
0009 #include <linux/of.h>
0010 #include <linux/mfd/syscon.h>
0011 #include <linux/regmap.h>
0012 
0013 #include "pmc.h"
0014 
0015 #define SAM9X5_USB_DIV_SHIFT    8
0016 #define SAM9X5_USB_MAX_DIV  0xf
0017 
0018 #define RM9200_USB_DIV_SHIFT    28
0019 #define RM9200_USB_DIV_TAB_SIZE 4
0020 
0021 #define SAM9X5_USBS_MASK    GENMASK(0, 0)
0022 #define SAM9X60_USBS_MASK   GENMASK(1, 0)
0023 
0024 struct at91sam9x5_clk_usb {
0025     struct clk_hw hw;
0026     struct regmap *regmap;
0027     struct at91_clk_pms pms;
0028     u32 usbs_mask;
0029     u8 num_parents;
0030 };
0031 
0032 #define to_at91sam9x5_clk_usb(hw) \
0033     container_of(hw, struct at91sam9x5_clk_usb, hw)
0034 
0035 struct at91rm9200_clk_usb {
0036     struct clk_hw hw;
0037     struct regmap *regmap;
0038     u32 divisors[4];
0039 };
0040 
0041 #define to_at91rm9200_clk_usb(hw) \
0042     container_of(hw, struct at91rm9200_clk_usb, hw)
0043 
0044 static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
0045                             unsigned long parent_rate)
0046 {
0047     struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
0048     unsigned int usbr;
0049     u8 usbdiv;
0050 
0051     regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
0052     usbdiv = (usbr & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;
0053 
0054     return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1));
0055 }
0056 
0057 static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
0058                          struct clk_rate_request *req)
0059 {
0060     struct clk_hw *parent;
0061     long best_rate = -EINVAL;
0062     unsigned long tmp_rate;
0063     int best_diff = -1;
0064     int tmp_diff;
0065     int i;
0066 
0067     for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
0068         int div;
0069 
0070         parent = clk_hw_get_parent_by_index(hw, i);
0071         if (!parent)
0072             continue;
0073 
0074         for (div = 1; div < SAM9X5_USB_MAX_DIV + 2; div++) {
0075             unsigned long tmp_parent_rate;
0076 
0077             tmp_parent_rate = req->rate * div;
0078             tmp_parent_rate = clk_hw_round_rate(parent,
0079                                tmp_parent_rate);
0080             if (!tmp_parent_rate)
0081                 continue;
0082 
0083             tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div);
0084             if (tmp_rate < req->rate)
0085                 tmp_diff = req->rate - tmp_rate;
0086             else
0087                 tmp_diff = tmp_rate - req->rate;
0088 
0089             if (best_diff < 0 || best_diff > tmp_diff) {
0090                 best_rate = tmp_rate;
0091                 best_diff = tmp_diff;
0092                 req->best_parent_rate = tmp_parent_rate;
0093                 req->best_parent_hw = parent;
0094             }
0095 
0096             if (!best_diff || tmp_rate < req->rate)
0097                 break;
0098         }
0099 
0100         if (!best_diff)
0101             break;
0102     }
0103 
0104     if (best_rate < 0)
0105         return best_rate;
0106 
0107     req->rate = best_rate;
0108     return 0;
0109 }
0110 
0111 static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
0112 {
0113     struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
0114 
0115     if (index >= usb->num_parents)
0116         return -EINVAL;
0117 
0118     regmap_update_bits(usb->regmap, AT91_PMC_USB, usb->usbs_mask, index);
0119 
0120     return 0;
0121 }
0122 
0123 static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw)
0124 {
0125     struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
0126     unsigned int usbr;
0127 
0128     regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
0129 
0130     return usbr & usb->usbs_mask;
0131 }
0132 
0133 static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
0134                        unsigned long parent_rate)
0135 {
0136     struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
0137     unsigned long div;
0138 
0139     if (!rate)
0140         return -EINVAL;
0141 
0142     div = DIV_ROUND_CLOSEST(parent_rate, rate);
0143     if (div > SAM9X5_USB_MAX_DIV + 1 || !div)
0144         return -EINVAL;
0145 
0146     regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_OHCIUSBDIV,
0147                (div - 1) << SAM9X5_USB_DIV_SHIFT);
0148 
0149     return 0;
0150 }
0151 
0152 static int at91sam9x5_usb_save_context(struct clk_hw *hw)
0153 {
0154     struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
0155     struct clk_hw *parent_hw = clk_hw_get_parent(hw);
0156 
0157     usb->pms.parent = at91sam9x5_clk_usb_get_parent(hw);
0158     usb->pms.parent_rate = clk_hw_get_rate(parent_hw);
0159     usb->pms.rate = at91sam9x5_clk_usb_recalc_rate(hw, usb->pms.parent_rate);
0160 
0161     return 0;
0162 }
0163 
0164 static void at91sam9x5_usb_restore_context(struct clk_hw *hw)
0165 {
0166     struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
0167     int ret;
0168 
0169     ret = at91sam9x5_clk_usb_set_parent(hw, usb->pms.parent);
0170     if (ret)
0171         return;
0172 
0173     at91sam9x5_clk_usb_set_rate(hw, usb->pms.rate, usb->pms.parent_rate);
0174 }
0175 
0176 static const struct clk_ops at91sam9x5_usb_ops = {
0177     .recalc_rate = at91sam9x5_clk_usb_recalc_rate,
0178     .determine_rate = at91sam9x5_clk_usb_determine_rate,
0179     .get_parent = at91sam9x5_clk_usb_get_parent,
0180     .set_parent = at91sam9x5_clk_usb_set_parent,
0181     .set_rate = at91sam9x5_clk_usb_set_rate,
0182     .save_context = at91sam9x5_usb_save_context,
0183     .restore_context = at91sam9x5_usb_restore_context,
0184 };
0185 
0186 static int at91sam9n12_clk_usb_enable(struct clk_hw *hw)
0187 {
0188     struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
0189 
0190     regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS,
0191                AT91_PMC_USBS);
0192 
0193     return 0;
0194 }
0195 
0196 static void at91sam9n12_clk_usb_disable(struct clk_hw *hw)
0197 {
0198     struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
0199 
0200     regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, 0);
0201 }
0202 
0203 static int at91sam9n12_clk_usb_is_enabled(struct clk_hw *hw)
0204 {
0205     struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
0206     unsigned int usbr;
0207 
0208     regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
0209 
0210     return usbr & AT91_PMC_USBS;
0211 }
0212 
0213 static const struct clk_ops at91sam9n12_usb_ops = {
0214     .enable = at91sam9n12_clk_usb_enable,
0215     .disable = at91sam9n12_clk_usb_disable,
0216     .is_enabled = at91sam9n12_clk_usb_is_enabled,
0217     .recalc_rate = at91sam9x5_clk_usb_recalc_rate,
0218     .determine_rate = at91sam9x5_clk_usb_determine_rate,
0219     .set_rate = at91sam9x5_clk_usb_set_rate,
0220 };
0221 
0222 static struct clk_hw * __init
0223 _at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
0224                  const char **parent_names, u8 num_parents,
0225                  u32 usbs_mask)
0226 {
0227     struct at91sam9x5_clk_usb *usb;
0228     struct clk_hw *hw;
0229     struct clk_init_data init;
0230     int ret;
0231 
0232     usb = kzalloc(sizeof(*usb), GFP_KERNEL);
0233     if (!usb)
0234         return ERR_PTR(-ENOMEM);
0235 
0236     init.name = name;
0237     init.ops = &at91sam9x5_usb_ops;
0238     init.parent_names = parent_names;
0239     init.num_parents = num_parents;
0240     init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
0241              CLK_SET_RATE_PARENT;
0242 
0243     usb->hw.init = &init;
0244     usb->regmap = regmap;
0245     usb->usbs_mask = usbs_mask;
0246     usb->num_parents = num_parents;
0247 
0248     hw = &usb->hw;
0249     ret = clk_hw_register(NULL, &usb->hw);
0250     if (ret) {
0251         kfree(usb);
0252         hw = ERR_PTR(ret);
0253     }
0254 
0255     return hw;
0256 }
0257 
0258 struct clk_hw * __init
0259 at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
0260                 const char **parent_names, u8 num_parents)
0261 {
0262     return _at91sam9x5_clk_register_usb(regmap, name, parent_names,
0263                         num_parents, SAM9X5_USBS_MASK);
0264 }
0265 
0266 struct clk_hw * __init
0267 sam9x60_clk_register_usb(struct regmap *regmap, const char *name,
0268              const char **parent_names, u8 num_parents)
0269 {
0270     return _at91sam9x5_clk_register_usb(regmap, name, parent_names,
0271                         num_parents, SAM9X60_USBS_MASK);
0272 }
0273 
0274 struct clk_hw * __init
0275 at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
0276                  const char *parent_name)
0277 {
0278     struct at91sam9x5_clk_usb *usb;
0279     struct clk_hw *hw;
0280     struct clk_init_data init;
0281     int ret;
0282 
0283     usb = kzalloc(sizeof(*usb), GFP_KERNEL);
0284     if (!usb)
0285         return ERR_PTR(-ENOMEM);
0286 
0287     init.name = name;
0288     init.ops = &at91sam9n12_usb_ops;
0289     init.parent_names = &parent_name;
0290     init.num_parents = 1;
0291     init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT;
0292 
0293     usb->hw.init = &init;
0294     usb->regmap = regmap;
0295 
0296     hw = &usb->hw;
0297     ret = clk_hw_register(NULL, &usb->hw);
0298     if (ret) {
0299         kfree(usb);
0300         hw = ERR_PTR(ret);
0301     }
0302 
0303     return hw;
0304 }
0305 
0306 static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw,
0307                             unsigned long parent_rate)
0308 {
0309     struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
0310     unsigned int pllbr;
0311     u8 usbdiv;
0312 
0313     regmap_read(usb->regmap, AT91_CKGR_PLLBR, &pllbr);
0314 
0315     usbdiv = (pllbr & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT;
0316     if (usb->divisors[usbdiv])
0317         return parent_rate / usb->divisors[usbdiv];
0318 
0319     return 0;
0320 }
0321 
0322 static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
0323                       unsigned long *parent_rate)
0324 {
0325     struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
0326     struct clk_hw *parent = clk_hw_get_parent(hw);
0327     unsigned long bestrate = 0;
0328     int bestdiff = -1;
0329     unsigned long tmprate;
0330     int tmpdiff;
0331     int i = 0;
0332 
0333     for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
0334         unsigned long tmp_parent_rate;
0335 
0336         if (!usb->divisors[i])
0337             continue;
0338 
0339         tmp_parent_rate = rate * usb->divisors[i];
0340         tmp_parent_rate = clk_hw_round_rate(parent, tmp_parent_rate);
0341         tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]);
0342         if (tmprate < rate)
0343             tmpdiff = rate - tmprate;
0344         else
0345             tmpdiff = tmprate - rate;
0346 
0347         if (bestdiff < 0 || bestdiff > tmpdiff) {
0348             bestrate = tmprate;
0349             bestdiff = tmpdiff;
0350             *parent_rate = tmp_parent_rate;
0351         }
0352 
0353         if (!bestdiff)
0354             break;
0355     }
0356 
0357     return bestrate;
0358 }
0359 
0360 static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
0361                        unsigned long parent_rate)
0362 {
0363     int i;
0364     struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
0365     unsigned long div;
0366 
0367     if (!rate)
0368         return -EINVAL;
0369 
0370     div = DIV_ROUND_CLOSEST(parent_rate, rate);
0371 
0372     for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
0373         if (usb->divisors[i] == div) {
0374             regmap_update_bits(usb->regmap, AT91_CKGR_PLLBR,
0375                        AT91_PMC_USBDIV,
0376                        i << RM9200_USB_DIV_SHIFT);
0377 
0378             return 0;
0379         }
0380     }
0381 
0382     return -EINVAL;
0383 }
0384 
0385 static const struct clk_ops at91rm9200_usb_ops = {
0386     .recalc_rate = at91rm9200_clk_usb_recalc_rate,
0387     .round_rate = at91rm9200_clk_usb_round_rate,
0388     .set_rate = at91rm9200_clk_usb_set_rate,
0389 };
0390 
0391 struct clk_hw * __init
0392 at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
0393                 const char *parent_name, const u32 *divisors)
0394 {
0395     struct at91rm9200_clk_usb *usb;
0396     struct clk_hw *hw;
0397     struct clk_init_data init;
0398     int ret;
0399 
0400     usb = kzalloc(sizeof(*usb), GFP_KERNEL);
0401     if (!usb)
0402         return ERR_PTR(-ENOMEM);
0403 
0404     init.name = name;
0405     init.ops = &at91rm9200_usb_ops;
0406     init.parent_names = &parent_name;
0407     init.num_parents = 1;
0408     init.flags = CLK_SET_RATE_PARENT;
0409 
0410     usb->hw.init = &init;
0411     usb->regmap = regmap;
0412     memcpy(usb->divisors, divisors, sizeof(usb->divisors));
0413 
0414     hw = &usb->hw;
0415     ret = clk_hw_register(NULL, &usb->hw);
0416     if (ret) {
0417         kfree(usb);
0418         hw = ERR_PTR(ret);
0419     }
0420 
0421     return hw;
0422 }