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 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 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 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