1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Driver for the Microchip SAMA7 USB 2.0 PHY Clock
4 *
5 * Copyright (C) 2024 Microchip Technology, Inc. and its subsidiaries
6 *
7 * Author: Tony Han <tony.han@microchip.com>
8 *
9 */
10
11 #include <drivers/atmel_rstc.h>
12 #include <io.h>
13 #include <kernel/delay.h>
14 #include <mm/core_memprot.h>
15 #include <sam_sfr.h>
16 #include "at91_clk.h"
17
18 #define SAMA7_SFR_UTMI0R(x) (0x2040 + 4 * (x)) /* offset of SFR_UTMI0Rx */
19 #define SAMA7_SFR_UTMI_COMMONON BIT(3) /* PLL Common ON bit */
20
21 struct sama7_utmi_clk {
22 vaddr_t base;
23 uint8_t id;
24 };
25
sama7_utmi_clk_enable(struct clk * hw)26 static TEE_Result sama7_utmi_clk_enable(struct clk *hw)
27 {
28 struct sama7_utmi_clk *utmi = hw->priv;
29 uint8_t id = utmi->id;
30
31 sam_rstc_usb_por(id, true);
32 io_clrbits32(utmi->base + SAMA7_SFR_UTMI0R(id),
33 SAMA7_SFR_UTMI_COMMONON);
34 sam_rstc_usb_por(id, false);
35
36 /* Datasheet states a minimum of 45 us before any USB operation */
37 udelay(50);
38
39 return TEE_SUCCESS;
40 }
41
sama7_utmi_clk_disable(struct clk * hw)42 static void sama7_utmi_clk_disable(struct clk *hw)
43 {
44 struct sama7_utmi_clk *utmi = hw->priv;
45 uint8_t id = utmi->id;
46
47 sam_rstc_usb_por(id, true);
48 io_setbits32(utmi->base + SAMA7_SFR_UTMI0R(id),
49 SAMA7_SFR_UTMI_COMMONON);
50 }
51
52 static const struct clk_ops sama7_utmi_ops = {
53 .enable = sama7_utmi_clk_enable,
54 .disable = sama7_utmi_clk_disable,
55 };
56
sama7_utmi_clk_register(const char * name,struct clk * parent,uint8_t id)57 struct clk *sama7_utmi_clk_register(const char *name,
58 struct clk *parent,
59 uint8_t id)
60 {
61 struct clk *hw = NULL;
62 struct sama7_utmi_clk *utmi_clk = NULL;
63
64 hw = clk_alloc(name, &sama7_utmi_ops, &parent, 1);
65 if (!hw)
66 return NULL;
67
68 utmi_clk = calloc(1, sizeof(*utmi_clk));
69 if (!utmi_clk) {
70 clk_free(hw);
71 return NULL;
72 }
73
74 utmi_clk->base = sam_sfr_base();
75 utmi_clk->id = id;
76 hw->priv = utmi_clk;
77
78 if (clk_register(hw)) {
79 clk_free(hw);
80 free(utmi_clk);
81 return NULL;
82 }
83
84 return hw;
85 }
86