1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2021 Linaro Ltd. 4 * Author: Sam Protsenko <semen.protsenko@linaro.org> 5 * 6 * Samsung Exynos USI driver (Universal Serial Interface). 7 */ 8 9 #include <linux/array_size.h> 10 #include <linux/clk.h> 11 #include <linux/mfd/syscon.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/of_platform.h> 15 #include <linux/platform_device.h> 16 #include <linux/regmap.h> 17 18 #include <dt-bindings/soc/samsung,exynos-usi.h> 19 20 /* USIv1: System Register: SW_CONF register bits */ 21 #define USI_V1_SW_CONF_NONE 0x0 22 #define USI_V1_SW_CONF_I2C0 0x1 23 #define USI_V1_SW_CONF_I2C1 0x2 24 #define USI_V1_SW_CONF_I2C0_1 0x3 25 #define USI_V1_SW_CONF_SPI 0x4 26 #define USI_V1_SW_CONF_UART 0x8 27 #define USI_V1_SW_CONF_UART_I2C1 0xa 28 #define USI_V1_SW_CONF_MASK (USI_V1_SW_CONF_I2C0 | USI_V1_SW_CONF_I2C1 | \ 29 USI_V1_SW_CONF_I2C0_1 | USI_V1_SW_CONF_SPI | \ 30 USI_V1_SW_CONF_UART | USI_V1_SW_CONF_UART_I2C1) 31 32 /* USIv2: System Register: SW_CONF register bits */ 33 #define USI_V2_SW_CONF_NONE 0x0 34 #define USI_V2_SW_CONF_UART BIT(0) 35 #define USI_V2_SW_CONF_SPI BIT(1) 36 #define USI_V2_SW_CONF_I2C BIT(2) 37 #define USI_V2_SW_CONF_MASK (USI_V2_SW_CONF_UART | USI_V2_SW_CONF_SPI | \ 38 USI_V2_SW_CONF_I2C) 39 40 /* USIv2: USI register offsets */ 41 #define USI_CON 0x04 42 #define USI_OPTION 0x08 43 44 /* USIv2: USI register bits */ 45 #define USI_CON_RESET BIT(0) 46 #define USI_OPTION_CLKREQ_ON BIT(1) 47 #define USI_OPTION_CLKSTOP_ON BIT(2) 48 49 enum exynos_usi_ver { 50 USI_VER1 = 0, 51 USI_VER2, 52 }; 53 54 struct exynos_usi_variant { 55 enum exynos_usi_ver ver; /* USI IP-core version */ 56 unsigned int sw_conf_mask; /* SW_CONF mask for all protocols */ 57 size_t min_mode; /* first index in exynos_usi_modes[] */ 58 size_t max_mode; /* last index in exynos_usi_modes[] */ 59 size_t num_clks; /* number of clocks to assert */ 60 const char * const *clk_names; /* clock names to assert */ 61 }; 62 63 struct exynos_usi { 64 struct device *dev; 65 void __iomem *regs; /* USI register map */ 66 struct clk_bulk_data *clks; /* USI clocks */ 67 68 size_t mode; /* current USI SW_CONF mode index */ 69 bool clkreq_on; /* always provide clock to IP */ 70 71 /* System Register */ 72 struct regmap *sysreg; /* System Register map */ 73 unsigned int sw_conf; /* SW_CONF register offset in sysreg */ 74 75 const struct exynos_usi_variant *data; 76 }; 77 78 struct exynos_usi_mode { 79 const char *name; /* mode name */ 80 unsigned int val; /* mode register value */ 81 }; 82 83 #define USI_MODES_MAX (USI_MODE_UART_I2C1 + 1) 84 static const struct exynos_usi_mode exynos_usi_modes[][USI_MODES_MAX] = { 85 [USI_VER1] = { 86 [USI_MODE_NONE] = { .name = "none", .val = USI_V1_SW_CONF_NONE }, 87 [USI_MODE_UART] = { .name = "uart", .val = USI_V1_SW_CONF_UART }, 88 [USI_MODE_SPI] = { .name = "spi", .val = USI_V1_SW_CONF_SPI }, 89 [USI_MODE_I2C] = { .name = "i2c", .val = USI_V1_SW_CONF_I2C0 }, 90 [USI_MODE_I2C1] = { .name = "i2c1", .val = USI_V1_SW_CONF_I2C1 }, 91 [USI_MODE_I2C0_1] = { .name = "i2c0_1", .val = USI_V1_SW_CONF_I2C0_1 }, 92 [USI_MODE_UART_I2C1] = { .name = "uart_i2c1", .val = USI_V1_SW_CONF_UART_I2C1 }, 93 }, [USI_VER2] = { 94 [USI_MODE_NONE] = { .name = "none", .val = USI_V2_SW_CONF_NONE }, 95 [USI_MODE_UART] = { .name = "uart", .val = USI_V2_SW_CONF_UART }, 96 [USI_MODE_SPI] = { .name = "spi", .val = USI_V2_SW_CONF_SPI }, 97 [USI_MODE_I2C] = { .name = "i2c", .val = USI_V2_SW_CONF_I2C }, 98 }, 99 }; 100 101 static const char * const exynos850_usi_clk_names[] = { "pclk", "ipclk" }; 102 static const struct exynos_usi_variant exynos850_usi_data = { 103 .ver = USI_VER2, 104 .sw_conf_mask = USI_V2_SW_CONF_MASK, 105 .min_mode = USI_MODE_NONE, 106 .max_mode = USI_MODE_I2C, 107 .num_clks = ARRAY_SIZE(exynos850_usi_clk_names), 108 .clk_names = exynos850_usi_clk_names, 109 }; 110 111 static const struct exynos_usi_variant exynos8895_usi_data = { 112 .ver = USI_VER1, 113 .sw_conf_mask = USI_V1_SW_CONF_MASK, 114 .min_mode = USI_MODE_NONE, 115 .max_mode = USI_MODE_UART_I2C1, 116 .num_clks = ARRAY_SIZE(exynos850_usi_clk_names), 117 .clk_names = exynos850_usi_clk_names, 118 }; 119 120 static const struct of_device_id exynos_usi_dt_match[] = { 121 { 122 .compatible = "samsung,exynos850-usi", 123 .data = &exynos850_usi_data, 124 }, { 125 .compatible = "samsung,exynos8895-usi", 126 .data = &exynos8895_usi_data, 127 }, 128 { } /* sentinel */ 129 }; 130 MODULE_DEVICE_TABLE(of, exynos_usi_dt_match); 131 132 /** 133 * exynos_usi_set_sw_conf - Set USI block configuration mode 134 * @usi: USI driver object 135 * @mode: Mode index 136 * 137 * Select underlying serial protocol (UART/SPI/I2C) in USI IP-core. 138 * 139 * Return: 0 on success, or negative error code on failure. 140 */ 141 static int exynos_usi_set_sw_conf(struct exynos_usi *usi, size_t mode) 142 { 143 unsigned int val; 144 int ret; 145 146 if (mode < usi->data->min_mode || mode > usi->data->max_mode) 147 return -EINVAL; 148 149 val = exynos_usi_modes[usi->data->ver][mode].val; 150 ret = regmap_update_bits(usi->sysreg, usi->sw_conf, 151 usi->data->sw_conf_mask, val); 152 if (ret) 153 return ret; 154 155 usi->mode = mode; 156 dev_dbg(usi->dev, "protocol: %s\n", 157 exynos_usi_modes[usi->data->ver][usi->mode].name); 158 159 return 0; 160 } 161 162 /** 163 * exynos_usi_enable - Initialize USI block 164 * @usi: USI driver object 165 * 166 * USI IP-core start state is "reset" (on startup and after CPU resume). This 167 * routine enables the USI block by clearing the reset flag. It also configures 168 * HWACG behavior (needed e.g. for UART Rx). It should be performed before 169 * underlying protocol becomes functional. 170 * 171 * Return: 0 on success, or negative error code on failure. 172 */ 173 static int exynos_usi_enable(const struct exynos_usi *usi) 174 { 175 u32 val; 176 int ret; 177 178 ret = clk_bulk_prepare_enable(usi->data->num_clks, usi->clks); 179 if (ret) 180 return ret; 181 182 /* Enable USI block */ 183 val = readl(usi->regs + USI_CON); 184 val &= ~USI_CON_RESET; 185 writel(val, usi->regs + USI_CON); 186 udelay(1); 187 188 /* Continuously provide the clock to USI IP w/o gating */ 189 if (usi->clkreq_on) { 190 val = readl(usi->regs + USI_OPTION); 191 val &= ~USI_OPTION_CLKSTOP_ON; 192 val |= USI_OPTION_CLKREQ_ON; 193 writel(val, usi->regs + USI_OPTION); 194 } 195 196 clk_bulk_disable_unprepare(usi->data->num_clks, usi->clks); 197 198 return ret; 199 } 200 201 static int exynos_usi_configure(struct exynos_usi *usi) 202 { 203 int ret; 204 205 ret = exynos_usi_set_sw_conf(usi, usi->mode); 206 if (ret) 207 return ret; 208 209 if (usi->data->ver == USI_VER1) 210 ret = clk_bulk_prepare_enable(usi->data->num_clks, 211 usi->clks); 212 else if (usi->data->ver == USI_VER2) 213 ret = exynos_usi_enable(usi); 214 215 return ret; 216 } 217 218 static void exynos_usi_unconfigure(void *data) 219 { 220 struct exynos_usi *usi = data; 221 u32 val; 222 int ret; 223 224 if (usi->data->ver == USI_VER1) { 225 clk_bulk_disable_unprepare(usi->data->num_clks, usi->clks); 226 return; 227 } 228 229 ret = clk_bulk_prepare_enable(usi->data->num_clks, usi->clks); 230 if (ret) 231 return; 232 233 /* Make sure that we've stopped providing the clock to USI IP */ 234 val = readl(usi->regs + USI_OPTION); 235 val &= ~USI_OPTION_CLKREQ_ON; 236 val |= USI_OPTION_CLKSTOP_ON; 237 writel(val, usi->regs + USI_OPTION); 238 239 /* Set USI block state to reset */ 240 val = readl(usi->regs + USI_CON); 241 val |= USI_CON_RESET; 242 writel(val, usi->regs + USI_CON); 243 244 clk_bulk_disable_unprepare(usi->data->num_clks, usi->clks); 245 } 246 247 static int exynos_usi_parse_dt(struct device_node *np, struct exynos_usi *usi) 248 { 249 int ret; 250 u32 mode; 251 252 ret = of_property_read_u32(np, "samsung,mode", &mode); 253 if (ret) 254 return ret; 255 if (mode < usi->data->min_mode || mode > usi->data->max_mode) 256 return -EINVAL; 257 usi->mode = mode; 258 259 usi->sysreg = syscon_regmap_lookup_by_phandle_args(np, "samsung,sysreg", 260 1, &usi->sw_conf); 261 if (IS_ERR(usi->sysreg)) 262 return PTR_ERR(usi->sysreg); 263 264 usi->clkreq_on = of_property_read_bool(np, "samsung,clkreq-on"); 265 266 return 0; 267 } 268 269 static int exynos_usi_get_clocks(struct exynos_usi *usi) 270 { 271 const size_t num = usi->data->num_clks; 272 struct device *dev = usi->dev; 273 size_t i; 274 275 if (num == 0) 276 return 0; 277 278 usi->clks = devm_kcalloc(dev, num, sizeof(*usi->clks), GFP_KERNEL); 279 if (!usi->clks) 280 return -ENOMEM; 281 282 for (i = 0; i < num; ++i) 283 usi->clks[i].id = usi->data->clk_names[i]; 284 285 return devm_clk_bulk_get(dev, num, usi->clks); 286 } 287 288 static int exynos_usi_probe(struct platform_device *pdev) 289 { 290 struct device *dev = &pdev->dev; 291 struct device_node *np = dev->of_node; 292 struct exynos_usi *usi; 293 int ret; 294 295 usi = devm_kzalloc(dev, sizeof(*usi), GFP_KERNEL); 296 if (!usi) 297 return -ENOMEM; 298 299 usi->dev = dev; 300 platform_set_drvdata(pdev, usi); 301 302 usi->data = of_device_get_match_data(dev); 303 if (!usi->data) 304 return -EINVAL; 305 306 ret = exynos_usi_parse_dt(np, usi); 307 if (ret) 308 return ret; 309 310 ret = exynos_usi_get_clocks(usi); 311 if (ret) 312 return ret; 313 314 if (usi->data->ver == USI_VER2) { 315 usi->regs = devm_platform_ioremap_resource(pdev, 0); 316 if (IS_ERR(usi->regs)) 317 return PTR_ERR(usi->regs); 318 } 319 320 ret = exynos_usi_configure(usi); 321 if (ret) 322 return ret; 323 324 ret = devm_add_action_or_reset(&pdev->dev, exynos_usi_unconfigure, usi); 325 if (ret) 326 return ret; 327 328 /* Make it possible to embed protocol nodes into USI np */ 329 return of_platform_populate(np, NULL, NULL, dev); 330 } 331 332 static int __maybe_unused exynos_usi_resume_noirq(struct device *dev) 333 { 334 struct exynos_usi *usi = dev_get_drvdata(dev); 335 336 return exynos_usi_configure(usi); 337 } 338 339 static const struct dev_pm_ops exynos_usi_pm = { 340 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, exynos_usi_resume_noirq) 341 }; 342 343 static struct platform_driver exynos_usi_driver = { 344 .driver = { 345 .name = "exynos-usi", 346 .pm = &exynos_usi_pm, 347 .of_match_table = exynos_usi_dt_match, 348 }, 349 .probe = exynos_usi_probe, 350 }; 351 module_platform_driver(exynos_usi_driver); 352 353 MODULE_DESCRIPTION("Samsung USI driver"); 354 MODULE_AUTHOR("Sam Protsenko <semen.protsenko@linaro.org>"); 355 MODULE_LICENSE("GPL"); 356