1 /* 2 * This file is provided under a dual BSD/GPLv2 license. When using or 3 * redistributing this file, you may do so under either license. 4 * 5 * GPL LICENSE SUMMARY 6 * 7 * Copyright (c) 2016 BayLibre, SAS. 8 * Author: Neil Armstrong <narmstrong@baylibre.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of version 2 of the GNU General Public License as 12 * published by the Free Software Foundation. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, see <http://www.gnu.org/licenses/>. 21 * The full GNU General Public License is included in this distribution 22 * in the file called COPYING. 23 * 24 * BSD LICENSE 25 * 26 * Copyright (c) 2016 BayLibre, SAS. 27 * Author: Neil Armstrong <narmstrong@baylibre.com> 28 * 29 * Redistribution and use in source and binary forms, with or without 30 * modification, are permitted provided that the following conditions 31 * are met: 32 * 33 * * Redistributions of source code must retain the above copyright 34 * notice, this list of conditions and the following disclaimer. 35 * * Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in 37 * the documentation and/or other materials provided with the 38 * distribution. 39 * * Neither the name of Intel Corporation nor the names of its 40 * contributors may be used to endorse or promote products derived 41 * from this software without specific prior written permission. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 */ 55 #include <linux/clk-provider.h> 56 #include <linux/of_address.h> 57 #include <linux/platform_device.h> 58 #include <linux/reset-controller.h> 59 #include <linux/init.h> 60 #include <dt-bindings/clock/gxbb-aoclkc.h> 61 #include <dt-bindings/reset/gxbb-aoclkc.h> 62 63 static DEFINE_SPINLOCK(gxbb_aoclk_lock); 64 65 struct gxbb_aoclk_reset_controller { 66 struct reset_controller_dev reset; 67 unsigned int *data; 68 void __iomem *base; 69 }; 70 71 static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev, 72 unsigned long id) 73 { 74 struct gxbb_aoclk_reset_controller *reset = 75 container_of(rcdev, struct gxbb_aoclk_reset_controller, reset); 76 77 writel(BIT(reset->data[id]), reset->base); 78 79 return 0; 80 } 81 82 static const struct reset_control_ops gxbb_aoclk_reset_ops = { 83 .reset = gxbb_aoclk_do_reset, 84 }; 85 86 #define GXBB_AO_GATE(_name, _bit) \ 87 static struct clk_gate _name##_ao = { \ 88 .reg = (void __iomem *)0, \ 89 .bit_idx = (_bit), \ 90 .lock = &gxbb_aoclk_lock, \ 91 .hw.init = &(struct clk_init_data) { \ 92 .name = #_name "_ao", \ 93 .ops = &clk_gate_ops, \ 94 .parent_names = (const char *[]){ "clk81" }, \ 95 .num_parents = 1, \ 96 .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ 97 }, \ 98 } 99 100 GXBB_AO_GATE(remote, 0); 101 GXBB_AO_GATE(i2c_master, 1); 102 GXBB_AO_GATE(i2c_slave, 2); 103 GXBB_AO_GATE(uart1, 3); 104 GXBB_AO_GATE(uart2, 5); 105 GXBB_AO_GATE(ir_blaster, 6); 106 107 static unsigned int gxbb_aoclk_reset[] = { 108 [RESET_AO_REMOTE] = 16, 109 [RESET_AO_I2C_MASTER] = 18, 110 [RESET_AO_I2C_SLAVE] = 19, 111 [RESET_AO_UART1] = 17, 112 [RESET_AO_UART2] = 22, 113 [RESET_AO_IR_BLASTER] = 23, 114 }; 115 116 static struct clk_gate *gxbb_aoclk_gate[] = { 117 [CLKID_AO_REMOTE] = &remote_ao, 118 [CLKID_AO_I2C_MASTER] = &i2c_master_ao, 119 [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao, 120 [CLKID_AO_UART1] = &uart1_ao, 121 [CLKID_AO_UART2] = &uart2_ao, 122 [CLKID_AO_IR_BLASTER] = &ir_blaster_ao, 123 }; 124 125 static struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { 126 .hws = { 127 [CLKID_AO_REMOTE] = &remote_ao.hw, 128 [CLKID_AO_I2C_MASTER] = &i2c_master_ao.hw, 129 [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao.hw, 130 [CLKID_AO_UART1] = &uart1_ao.hw, 131 [CLKID_AO_UART2] = &uart2_ao.hw, 132 [CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw, 133 }, 134 .num = ARRAY_SIZE(gxbb_aoclk_gate), 135 }; 136 137 static int gxbb_aoclkc_probe(struct platform_device *pdev) 138 { 139 struct resource *res; 140 void __iomem *base; 141 int ret, clkid; 142 struct device *dev = &pdev->dev; 143 struct gxbb_aoclk_reset_controller *rstc; 144 145 rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL); 146 if (!rstc) 147 return -ENOMEM; 148 149 /* Generic clocks */ 150 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 151 base = devm_ioremap_resource(dev, res); 152 if (IS_ERR(base)) 153 return PTR_ERR(base); 154 155 /* Reset Controller */ 156 rstc->base = base; 157 rstc->data = gxbb_aoclk_reset; 158 rstc->reset.ops = &gxbb_aoclk_reset_ops; 159 rstc->reset.nr_resets = ARRAY_SIZE(gxbb_aoclk_reset); 160 rstc->reset.of_node = dev->of_node; 161 ret = devm_reset_controller_register(dev, &rstc->reset); 162 163 /* 164 * Populate base address and register all clks 165 */ 166 for (clkid = 0; clkid < gxbb_aoclk_onecell_data.num; clkid++) { 167 gxbb_aoclk_gate[clkid]->reg = base; 168 169 ret = devm_clk_hw_register(dev, 170 gxbb_aoclk_onecell_data.hws[clkid]); 171 if (ret) 172 return ret; 173 } 174 175 return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, 176 &gxbb_aoclk_onecell_data); 177 } 178 179 static const struct of_device_id gxbb_aoclkc_match_table[] = { 180 { .compatible = "amlogic,gxbb-aoclkc" }, 181 { } 182 }; 183 184 static struct platform_driver gxbb_aoclkc_driver = { 185 .probe = gxbb_aoclkc_probe, 186 .driver = { 187 .name = "gxbb-aoclkc", 188 .of_match_table = gxbb_aoclkc_match_table, 189 }, 190 }; 191 builtin_platform_driver(gxbb_aoclkc_driver); 192