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