1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Texas Instruments CDCE913/925/937/949 clock synthesizer driver 4 * 5 * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/ 6 * Tero Kristo <t-kristo@ti.com> 7 * 8 * Based on Linux kernel clk-cdce925.c. 9 */ 10 11#include <dm.h> 12#include <errno.h> 13#include <clk-uclass.h> 14#include <i2c.h> 15#include <dm/device_compat.h> 16#include <linux/bitops.h> 17 18#define MAX_NUMBER_OF_PLLS 4 19#define MAX_NUMER_OF_OUTPUTS 9 20 21#define CDCE9XX_REG_GLOBAL1 0x01 22#define CDCE9XX_REG_Y1SPIPDIVH 0x02 23#define CDCE9XX_REG_PDIV1L 0x03 24#define CDCE9XX_REG_XCSEL 0x05 25 26#define CDCE9XX_PDIV1_H_MASK 0x3 27 28#define CDCE9XX_REG_PDIV(clk) (0x16 + (((clk) - 1) & 1) + \ 29 ((clk) - 1) / 2 * 0x10) 30 31#define CDCE9XX_PDIV_MASK 0x7f 32 33#define CDCE9XX_BYTE_TRANSFER BIT(7) 34 35struct cdce9xx_chip_info { 36 int num_plls; 37 int num_outputs; 38}; 39 40struct cdce9xx_clk_data { 41 struct udevice *i2c; 42 struct cdce9xx_chip_info *chip; 43 u32 xtal_rate; 44}; 45 46static const struct cdce9xx_chip_info cdce913_chip_info = { 47 .num_plls = 1, .num_outputs = 3, 48}; 49 50static const struct cdce9xx_chip_info cdce925_chip_info = { 51 .num_plls = 2, .num_outputs = 5, 52}; 53 54static const struct cdce9xx_chip_info cdce937_chip_info = { 55 .num_plls = 3, .num_outputs = 7, 56}; 57 58static const struct cdce9xx_chip_info cdce949_chip_info = { 59 .num_plls = 4, .num_outputs = 9, 60}; 61 62static int cdce9xx_reg_read(struct udevice *dev, u8 addr, u8 *buf) 63{ 64 struct cdce9xx_clk_data *data = dev_get_priv(dev); 65 int ret; 66 67 ret = dm_i2c_read(data->i2c, addr | CDCE9XX_BYTE_TRANSFER, buf, 1); 68 if (ret) 69 dev_err(dev, "%s: failed for addr:%x, ret:%d\n", __func__, 70 addr, ret); 71 72 return ret; 73} 74 75static int cdce9xx_reg_write(struct udevice *dev, u8 addr, u8 val) 76{ 77 struct cdce9xx_clk_data *data = dev_get_priv(dev); 78 int ret; 79 80 ret = dm_i2c_write(data->i2c, addr | CDCE9XX_BYTE_TRANSFER, &val, 1); 81 if (ret) 82 dev_err(dev, "%s: failed for addr:%x, ret:%d\n", __func__, 83 addr, ret); 84 85 return ret; 86} 87 88static int cdce9xx_clk_request(struct clk *clk) 89{ 90 struct cdce9xx_clk_data *data = dev_get_priv(clk->dev); 91 92 if (clk->id > data->chip->num_outputs) 93 return -EINVAL; 94 95 return 0; 96} 97 98static int cdce9xx_clk_probe(struct udevice *dev) 99{ 100 struct cdce9xx_clk_data *data = dev_get_priv(dev); 101 struct cdce9xx_chip_info *chip = (void *)dev_get_driver_data(dev); 102 int ret; 103 u32 val; 104 struct clk clk; 105 106 val = (u32)dev_read_addr_ptr(dev); 107 108 ret = i2c_get_chip(dev->parent, val, 1, &data->i2c); 109 if (ret) { 110 dev_err(dev, "I2C probe failed.\n"); 111 return ret; 112 } 113 114 data->chip = chip; 115 116 ret = clk_get_by_index(dev, 0, &clk); 117 data->xtal_rate = clk_get_rate(&clk); 118 119 val = dev_read_u32_default(dev, "xtal-load-pf", -1); 120 if (val >= 0) 121 cdce9xx_reg_write(dev, CDCE9XX_REG_XCSEL, val << 3); 122 123 return 0; 124} 125 126static u16 cdce9xx_clk_get_pdiv(struct clk *clk) 127{ 128 u8 val; 129 u16 pdiv; 130 int ret; 131 132 if (clk->id == 0) { 133 ret = cdce9xx_reg_read(clk->dev, CDCE9XX_REG_Y1SPIPDIVH, &val); 134 if (ret) 135 return 0; 136 137 pdiv = (val & CDCE9XX_PDIV1_H_MASK) << 8; 138 139 ret = cdce9xx_reg_read(clk->dev, CDCE9XX_REG_PDIV1L, &val); 140 if (ret) 141 return 0; 142 143 pdiv |= val; 144 } else { 145 ret = cdce9xx_reg_read(clk->dev, CDCE9XX_REG_PDIV(clk->id), 146 &val); 147 if (ret) 148 return 0; 149 150 pdiv = val & CDCE9XX_PDIV_MASK; 151 } 152 153 return pdiv; 154} 155 156static u32 cdce9xx_clk_get_parent_rate(struct clk *clk) 157{ 158 struct cdce9xx_clk_data *data = dev_get_priv(clk->dev); 159 160 return data->xtal_rate; 161} 162 163static ulong cdce9xx_clk_get_rate(struct clk *clk) 164{ 165 u32 parent_rate; 166 u16 pdiv; 167 168 parent_rate = cdce9xx_clk_get_parent_rate(clk); 169 170 pdiv = cdce9xx_clk_get_pdiv(clk); 171 172 return parent_rate / pdiv; 173} 174 175static ulong cdce9xx_clk_set_rate(struct clk *clk, ulong rate) 176{ 177 u32 parent_rate; 178 int pdiv; 179 u32 diff; 180 u8 val; 181 int ret; 182 183 parent_rate = cdce9xx_clk_get_parent_rate(clk); 184 185 pdiv = parent_rate / rate; 186 187 diff = rate - parent_rate / pdiv; 188 189 if (rate - parent_rate / (pdiv + 1) < diff) 190 pdiv++; 191 192 if (clk->id == 0) { 193 ret = cdce9xx_reg_read(clk->dev, CDCE9XX_REG_Y1SPIPDIVH, &val); 194 if (ret) 195 return ret; 196 197 val &= ~CDCE9XX_PDIV1_H_MASK; 198 199 val |= (pdiv >> 8); 200 201 ret = cdce9xx_reg_write(clk->dev, CDCE9XX_REG_Y1SPIPDIVH, val); 202 if (ret) 203 return ret; 204 205 ret = cdce9xx_reg_write(clk->dev, CDCE9XX_REG_PDIV1L, 206 (pdiv & 0xff)); 207 if (ret) 208 return ret; 209 } else { 210 ret = cdce9xx_reg_read(clk->dev, CDCE9XX_REG_PDIV(clk->id), 211 &val); 212 if (ret) 213 return ret; 214 215 val &= ~CDCE9XX_PDIV_MASK; 216 217 val |= pdiv; 218 219 ret = cdce9xx_reg_write(clk->dev, CDCE9XX_REG_PDIV(clk->id), 220 val); 221 if (ret) 222 return ret; 223 } 224 225 return 0; 226} 227 228static const struct udevice_id cdce9xx_clk_of_match[] = { 229 { .compatible = "ti,cdce913", .data = (u32)&cdce913_chip_info }, 230 { .compatible = "ti,cdce925", .data = (u32)&cdce925_chip_info }, 231 { .compatible = "ti,cdce937", .data = (u32)&cdce937_chip_info }, 232 { .compatible = "ti,cdce949", .data = (u32)&cdce949_chip_info }, 233 { /* sentinel */ }, 234}; 235 236static const struct clk_ops cdce9xx_clk_ops = { 237 .request = cdce9xx_clk_request, 238 .get_rate = cdce9xx_clk_get_rate, 239 .set_rate = cdce9xx_clk_set_rate, 240}; 241 242U_BOOT_DRIVER(cdce9xx_clk) = { 243 .name = "cdce9xx-clk", 244 .id = UCLASS_CLK, 245 .of_match = cdce9xx_clk_of_match, 246 .probe = cdce9xx_clk_probe, 247 .priv_auto = sizeof(struct cdce9xx_clk_data), 248 .ops = &cdce9xx_clk_ops, 249}; 250