1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 /* 3 * Copyright (c) 2016 BayLibre, SAS. 4 * Author: Neil Armstrong <narmstrong@baylibre.com> 5 */ 6 #include <linux/platform_device.h> 7 #include <linux/mfd/syscon.h> 8 #include "clk-regmap.h" 9 #include "meson-aoclk.h" 10 #include "gxbb-aoclk.h" 11 12 #define GXBB_AO_GATE(_name, _bit) \ 13 static struct clk_regmap _name##_ao = { \ 14 .data = &(struct clk_regmap_gate_data) { \ 15 .offset = AO_RTI_GEN_CNTL_REG0, \ 16 .bit_idx = (_bit), \ 17 }, \ 18 .hw.init = &(struct clk_init_data) { \ 19 .name = #_name "_ao", \ 20 .ops = &clk_regmap_gate_ops, \ 21 .parent_names = (const char *[]){ "clk81" }, \ 22 .num_parents = 1, \ 23 .flags = CLK_IGNORE_UNUSED, \ 24 }, \ 25 } 26 27 GXBB_AO_GATE(remote, 0); 28 GXBB_AO_GATE(i2c_master, 1); 29 GXBB_AO_GATE(i2c_slave, 2); 30 GXBB_AO_GATE(uart1, 3); 31 GXBB_AO_GATE(uart2, 5); 32 GXBB_AO_GATE(ir_blaster, 6); 33 34 static struct aoclk_cec_32k cec_32k_ao = { 35 .hw.init = &(struct clk_init_data) { 36 .name = "cec_32k_ao", 37 .ops = &meson_aoclk_cec_32k_ops, 38 .parent_names = (const char *[]){ "xtal" }, 39 .num_parents = 1, 40 .flags = CLK_IGNORE_UNUSED, 41 }, 42 }; 43 44 static const unsigned int gxbb_aoclk_reset[] = { 45 [RESET_AO_REMOTE] = 16, 46 [RESET_AO_I2C_MASTER] = 18, 47 [RESET_AO_I2C_SLAVE] = 19, 48 [RESET_AO_UART1] = 17, 49 [RESET_AO_UART2] = 22, 50 [RESET_AO_IR_BLASTER] = 23, 51 }; 52 53 static struct clk_regmap *gxbb_aoclk_gate[] = { 54 [CLKID_AO_REMOTE] = &remote_ao, 55 [CLKID_AO_I2C_MASTER] = &i2c_master_ao, 56 [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao, 57 [CLKID_AO_UART1] = &uart1_ao, 58 [CLKID_AO_UART2] = &uart2_ao, 59 [CLKID_AO_IR_BLASTER] = &ir_blaster_ao, 60 }; 61 62 static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { 63 .hws = { 64 [CLKID_AO_REMOTE] = &remote_ao.hw, 65 [CLKID_AO_I2C_MASTER] = &i2c_master_ao.hw, 66 [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao.hw, 67 [CLKID_AO_UART1] = &uart1_ao.hw, 68 [CLKID_AO_UART2] = &uart2_ao.hw, 69 [CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw, 70 [CLKID_AO_CEC_32K] = &cec_32k_ao.hw, 71 }, 72 .num = NR_CLKS, 73 }; 74 75 static int gxbb_register_cec_ao_32k(struct platform_device *pdev) 76 { 77 struct device *dev = &pdev->dev; 78 struct regmap *regmap; 79 int ret; 80 81 regmap = syscon_node_to_regmap(of_get_parent(dev->of_node)); 82 if (IS_ERR(regmap)) { 83 dev_err(dev, "failed to get regmap\n"); 84 return PTR_ERR(regmap); 85 } 86 87 /* Specific clocks */ 88 cec_32k_ao.regmap = regmap; 89 ret = devm_clk_hw_register(dev, &cec_32k_ao.hw); 90 if (ret) { 91 dev_err(&pdev->dev, "clk cec_32k_ao register failed.\n"); 92 return ret; 93 } 94 95 return 0; 96 } 97 98 static const struct meson_aoclk_data gxbb_aoclkc_data = { 99 .reset_reg = AO_RTI_GEN_CNTL_REG0, 100 .num_reset = ARRAY_SIZE(gxbb_aoclk_reset), 101 .reset = gxbb_aoclk_reset, 102 .num_clks = ARRAY_SIZE(gxbb_aoclk_gate), 103 .clks = gxbb_aoclk_gate, 104 .hw_data = &gxbb_aoclk_onecell_data, 105 }; 106 107 static int gxbb_aoclkc_probe(struct platform_device *pdev) 108 { 109 int ret = gxbb_register_cec_ao_32k(pdev); 110 if (ret) 111 return ret; 112 113 return meson_aoclkc_probe(pdev); 114 } 115 116 static const struct of_device_id gxbb_aoclkc_match_table[] = { 117 { 118 .compatible = "amlogic,meson-gx-aoclkc", 119 .data = &gxbb_aoclkc_data, 120 }, 121 { } 122 }; 123 124 static struct platform_driver gxbb_aoclkc_driver = { 125 .probe = gxbb_aoclkc_probe, 126 .driver = { 127 .name = "gxbb-aoclkc", 128 .of_match_table = gxbb_aoclkc_match_table, 129 }, 130 }; 131 builtin_platform_driver(gxbb_aoclkc_driver); 132