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