xref: /optee_os/core/drivers/clk/sam/phy-sama7-utmi-clk.c (revision 29f0ec7152e4d58d19745d8910b43ccdb62e2e1d)
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