1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2019 Western Digital Corporation or its affiliates. 4 * 5 * Author: Anup Patel <anup.patel@wdc.com> 6 */ 7 8 #include <common.h> 9 #include <clk-uclass.h> 10 #include <div64.h> 11 #include <dm.h> 12 13 struct clk_fixed_factor { 14 struct clk parent; 15 unsigned int div; 16 unsigned int mult; 17 }; 18 19 #define to_clk_fixed_factor(dev) \ 20 ((struct clk_fixed_factor *)dev_get_platdata(dev)) 21 22 static ulong clk_fixed_factor_get_rate(struct clk *clk) 23 { 24 uint64_t rate; 25 struct clk_fixed_factor *ff = to_clk_fixed_factor(clk->dev); 26 27 if (clk->id != 0) 28 return -EINVAL; 29 30 rate = clk_get_rate(&ff->parent); 31 if (IS_ERR_VALUE(rate)) 32 return rate; 33 34 do_div(rate, ff->div); 35 36 return rate * ff->mult; 37 } 38 39 const struct clk_ops clk_fixed_factor_ops = { 40 .get_rate = clk_fixed_factor_get_rate, 41 }; 42 43 static int clk_fixed_factor_ofdata_to_platdata(struct udevice *dev) 44 { 45 #if !CONFIG_IS_ENABLED(OF_PLATDATA) 46 int err; 47 struct clk_fixed_factor *ff = to_clk_fixed_factor(dev); 48 49 err = clk_get_by_index(dev, 0, &ff->parent); 50 if (err) 51 return err; 52 53 ff->div = dev_read_u32_default(dev, "clock-div", 1); 54 ff->mult = dev_read_u32_default(dev, "clock-mult", 1); 55 #endif 56 57 return 0; 58 } 59 60 static const struct udevice_id clk_fixed_factor_match[] = { 61 { 62 .compatible = "fixed-factor-clock", 63 }, 64 { /* sentinel */ } 65 }; 66 67 U_BOOT_DRIVER(clk_fixed_factor) = { 68 .name = "fixed_factor_clock", 69 .id = UCLASS_CLK, 70 .of_match = clk_fixed_factor_match, 71 .ofdata_to_platdata = clk_fixed_factor_ofdata_to_platdata, 72 .platdata_auto_alloc_size = sizeof(struct clk_fixed_factor), 73 .ops = &clk_fixed_factor_ops, 74 }; 75