1 /* 2 * Copyright (C) 2016 Imagination Technologies 3 * 4 * SPDX-License-Identifier: GPL-2.0 5 */ 6 7 #include <common.h> 8 #include <clk-uclass.h> 9 #include <dm.h> 10 #include <dt-bindings/clock/boston-clock.h> 11 #include <regmap.h> 12 #include <syscon.h> 13 14 struct clk_boston { 15 struct regmap *regmap; 16 }; 17 18 #define BOSTON_PLAT_MMCMDIV 0x30 19 # define BOSTON_PLAT_MMCMDIV_CLK0DIV (0xff << 0) 20 # define BOSTON_PLAT_MMCMDIV_INPUT (0xff << 8) 21 # define BOSTON_PLAT_MMCMDIV_MUL (0xff << 16) 22 # define BOSTON_PLAT_MMCMDIV_CLK1DIV (0xff << 24) 23 24 static uint32_t ext_field(uint32_t val, uint32_t mask) 25 { 26 return (val & mask) >> (ffs(mask) - 1); 27 } 28 29 static ulong clk_boston_get_rate(struct clk *clk) 30 { 31 struct clk_boston *state = dev_get_platdata(clk->dev); 32 uint32_t in_rate, mul, div; 33 uint mmcmdiv; 34 int err; 35 36 err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv); 37 if (err) 38 return 0; 39 40 in_rate = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_INPUT); 41 mul = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_MUL); 42 43 switch (clk->id) { 44 case BOSTON_CLK_SYS: 45 div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK0DIV); 46 break; 47 case BOSTON_CLK_CPU: 48 div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK1DIV); 49 break; 50 default: 51 return 0; 52 } 53 54 return (in_rate * mul * 1000000) / div; 55 } 56 57 const struct clk_ops clk_boston_ops = { 58 .get_rate = clk_boston_get_rate, 59 }; 60 61 static int clk_boston_ofdata_to_platdata(struct udevice *dev) 62 { 63 struct clk_boston *state = dev_get_platdata(dev); 64 struct udevice *syscon; 65 int err; 66 67 err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, 68 "regmap", &syscon); 69 if (err) { 70 error("unable to find syscon device\n"); 71 return err; 72 } 73 74 state->regmap = syscon_get_regmap(syscon); 75 if (!state->regmap) { 76 error("unable to find regmap\n"); 77 return -ENODEV; 78 } 79 80 return 0; 81 } 82 83 static const struct udevice_id clk_boston_match[] = { 84 { 85 .compatible = "img,boston-clock", 86 }, 87 { /* sentinel */ } 88 }; 89 90 U_BOOT_DRIVER(clk_boston) = { 91 .name = "boston_clock", 92 .id = UCLASS_CLK, 93 .of_match = clk_boston_match, 94 .ofdata_to_platdata = clk_boston_ofdata_to_platdata, 95 .platdata_auto_alloc_size = sizeof(struct clk_boston), 96 .ops = &clk_boston_ops, 97 }; 98