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/mfd/syscon.h> 60 #include <linux/regmap.h> 61 #include <linux/init.h> 62 #include <linux/delay.h> 63 #include <dt-bindings/clock/gxbb-aoclkc.h> 64 #include <dt-bindings/reset/gxbb-aoclkc.h> 65 #include "gxbb-aoclk.h" 66 67 static DEFINE_SPINLOCK(gxbb_aoclk_lock); 68 69 struct gxbb_aoclk_reset_controller { 70 struct reset_controller_dev reset; 71 unsigned int *data; 72 struct regmap *regmap; 73 }; 74 75 static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev, 76 unsigned long id) 77 { 78 struct gxbb_aoclk_reset_controller *reset = 79 container_of(rcdev, struct gxbb_aoclk_reset_controller, reset); 80 81 return regmap_write(reset->regmap, AO_RTI_GEN_CNTL_REG0, 82 BIT(reset->data[id])); 83 } 84 85 static const struct reset_control_ops gxbb_aoclk_reset_ops = { 86 .reset = gxbb_aoclk_do_reset, 87 }; 88 89 #define GXBB_AO_GATE(_name, _bit) \ 90 static struct aoclk_gate_regmap _name##_ao = { \ 91 .bit_idx = (_bit), \ 92 .lock = &gxbb_aoclk_lock, \ 93 .hw.init = &(struct clk_init_data) { \ 94 .name = #_name "_ao", \ 95 .ops = &meson_aoclk_gate_regmap_ops, \ 96 .parent_names = (const char *[]){ "clk81" }, \ 97 .num_parents = 1, \ 98 .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ 99 }, \ 100 } 101 102 GXBB_AO_GATE(remote, 0); 103 GXBB_AO_GATE(i2c_master, 1); 104 GXBB_AO_GATE(i2c_slave, 2); 105 GXBB_AO_GATE(uart1, 3); 106 GXBB_AO_GATE(uart2, 5); 107 GXBB_AO_GATE(ir_blaster, 6); 108 109 static struct aoclk_cec_32k cec_32k_ao = { 110 .lock = &gxbb_aoclk_lock, 111 .hw.init = &(struct clk_init_data) { 112 .name = "cec_32k_ao", 113 .ops = &meson_aoclk_cec_32k_ops, 114 .parent_names = (const char *[]){ "xtal" }, 115 .num_parents = 1, 116 .flags = CLK_IGNORE_UNUSED, 117 }, 118 }; 119 120 static unsigned int gxbb_aoclk_reset[] = { 121 [RESET_AO_REMOTE] = 16, 122 [RESET_AO_I2C_MASTER] = 18, 123 [RESET_AO_I2C_SLAVE] = 19, 124 [RESET_AO_UART1] = 17, 125 [RESET_AO_UART2] = 22, 126 [RESET_AO_IR_BLASTER] = 23, 127 }; 128 129 static struct aoclk_gate_regmap *gxbb_aoclk_gate[] = { 130 [CLKID_AO_REMOTE] = &remote_ao, 131 [CLKID_AO_I2C_MASTER] = &i2c_master_ao, 132 [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao, 133 [CLKID_AO_UART1] = &uart1_ao, 134 [CLKID_AO_UART2] = &uart2_ao, 135 [CLKID_AO_IR_BLASTER] = &ir_blaster_ao, 136 }; 137 138 static struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { 139 .hws = { 140 [CLKID_AO_REMOTE] = &remote_ao.hw, 141 [CLKID_AO_I2C_MASTER] = &i2c_master_ao.hw, 142 [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao.hw, 143 [CLKID_AO_UART1] = &uart1_ao.hw, 144 [CLKID_AO_UART2] = &uart2_ao.hw, 145 [CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw, 146 [CLKID_AO_CEC_32K] = &cec_32k_ao.hw, 147 }, 148 .num = 7, 149 }; 150 151 static int gxbb_aoclkc_probe(struct platform_device *pdev) 152 { 153 struct gxbb_aoclk_reset_controller *rstc; 154 struct device *dev = &pdev->dev; 155 struct regmap *regmap; 156 int ret, clkid; 157 158 rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL); 159 if (!rstc) 160 return -ENOMEM; 161 162 regmap = syscon_node_to_regmap(of_get_parent(dev->of_node)); 163 if (IS_ERR(regmap)) { 164 dev_err(dev, "failed to get regmap\n"); 165 return -ENODEV; 166 } 167 168 /* Reset Controller */ 169 rstc->regmap = regmap; 170 rstc->data = gxbb_aoclk_reset; 171 rstc->reset.ops = &gxbb_aoclk_reset_ops; 172 rstc->reset.nr_resets = ARRAY_SIZE(gxbb_aoclk_reset); 173 rstc->reset.of_node = dev->of_node; 174 ret = devm_reset_controller_register(dev, &rstc->reset); 175 176 /* 177 * Populate regmap and register all clks 178 */ 179 for (clkid = 0; clkid < ARRAY_SIZE(gxbb_aoclk_gate); clkid++) { 180 gxbb_aoclk_gate[clkid]->regmap = regmap; 181 182 ret = devm_clk_hw_register(dev, 183 gxbb_aoclk_onecell_data.hws[clkid]); 184 if (ret) 185 return ret; 186 } 187 188 /* Specific clocks */ 189 cec_32k_ao.regmap = regmap; 190 ret = devm_clk_hw_register(dev, &cec_32k_ao.hw); 191 if (ret) 192 return ret; 193 194 return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, 195 &gxbb_aoclk_onecell_data); 196 } 197 198 static const struct of_device_id gxbb_aoclkc_match_table[] = { 199 { .compatible = "amlogic,meson-gx-aoclkc" }, 200 { } 201 }; 202 203 static struct platform_driver gxbb_aoclkc_driver = { 204 .probe = gxbb_aoclkc_probe, 205 .driver = { 206 .name = "gxbb-aoclkc", 207 .of_match_table = gxbb_aoclkc_match_table, 208 }, 209 }; 210 builtin_platform_driver(gxbb_aoclkc_driver); 211