1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2016 Atmel Corporation 4 * Wenyou.Yang <wenyou.yang@atmel.com> 5 */ 6 7#include <common.h> 8#include <asm/io.h> 9#include <clk-uclass.h> 10#include <linux/clk-provider.h> 11#include "pmc.h" 12 13static int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) 14{ 15 if (args->args_count != 2) { 16 debug("AT91: clk: Invalid args_count: %d\n", args->args_count); 17 return -EINVAL; 18 } 19 20 clk->id = AT91_TO_CLK_ID(args->args[0], args->args[1]); 21 22 return 0; 23} 24 25const struct clk_ops at91_clk_ops = { 26 .of_xlate = at91_clk_of_xlate, 27 .set_rate = ccf_clk_set_rate, 28 .get_rate = ccf_clk_get_rate, 29 .enable = ccf_clk_enable, 30 .disable = ccf_clk_disable, 31}; 32 33/** 34 * pmc_read() - read content at address base + off into val 35 * 36 * @base: base address 37 * @off: offset to read from 38 * @val: where the content of base + off is stored 39 * 40 * @return: void 41 */ 42void pmc_read(void __iomem *base, unsigned int off, unsigned int *val) 43{ 44 *val = readl(base + off); 45} 46 47/** 48 * pmc_write() - write content of val at address base + off 49 * 50 * @base: base address 51 * @off: offset to write to 52 * @val: content to be written at base + off 53 * 54 * @return: void 55 */ 56void pmc_write(void __iomem *base, unsigned int off, unsigned int val) 57{ 58 writel(val, base + off); 59} 60 61/** 62 * pmc_update_bits() - update a set of bits at address base + off 63 * 64 * @base: base address 65 * @off: offset to be updated 66 * @mask: mask of bits to be updated 67 * @bits: the new value to be updated 68 * 69 * @return: void 70 */ 71void pmc_update_bits(void __iomem *base, unsigned int off, 72 unsigned int mask, unsigned int bits) 73{ 74 unsigned int tmp; 75 76 tmp = readl(base + off); 77 tmp &= ~mask; 78 writel(tmp | (bits & mask), base + off); 79} 80 81/** 82 * at91_clk_mux_val_to_index() - get parent index in mux table 83 * 84 * @table: clock mux table 85 * @num_parents: clock number of parents 86 * @val: clock id who's mux index should be retrieved 87 * 88 * @return: clock index in mux table or a negative error number in case of 89 * failure 90 */ 91int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val) 92{ 93 int i; 94 95 if (!table || !num_parents) 96 return -EINVAL; 97 98 for (i = 0; i < num_parents; i++) { 99 if (table[i] == val) 100 return i; 101 } 102 103 return -EINVAL; 104} 105 106/** 107 * at91_clk_mux_index_to_val() - get parent ID corresponding to an entry in 108 * clock's mux table 109 * 110 * @table: clock's mux table 111 * @num_parents: clock's number of parents 112 * @index: index in mux table which clock's ID should be retrieved 113 * 114 * @return: clock ID or a negative error number in case of failure 115 */ 116int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index) 117{ 118 if (!table || !num_parents || index < 0 || index > num_parents) 119 return -EINVAL; 120 121 return table[index]; 122} 123 124int at91_clk_setup(const struct pmc_clk_setup *setup, int size) 125{ 126 struct clk *c, *parent; 127 int i, ret; 128 129 if (!size) 130 return 0; 131 132 if (!setup) 133 return -EINVAL; 134 135 for (i = 0; i < size; i++) { 136 ret = clk_get_by_id(setup[i].cid, &c); 137 if (ret) 138 return ret; 139 140 if (setup[i].pid) { 141 ret = clk_get_by_id(setup[i].pid, &parent); 142 if (ret) 143 return ret; 144 145 ret = clk_set_parent(c, parent); 146 if (ret) 147 return ret; 148 149 if (setup[i].prate) { 150 ret = clk_set_rate(parent, setup[i].prate); 151 if (ret < 0) 152 return ret; 153 } 154 } 155 156 if (setup[i].rate) { 157 ret = clk_set_rate(c, setup[i].rate); 158 if (ret < 0) 159 return ret; 160 } 161 } 162 163 return 0; 164} 165