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