Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'sunxi-clocks-for-4.7' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into clk-next

Pull Allwinner clock driver updates from Maxime Ripard:

As usual, a bunch of clocks patches for 4.7, mostly fixes and cleanups, and
display-related clocks.

* tag 'sunxi-clocks-for-4.7' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux:
clk: sunxi: Let divs clocks read the base factor clock name from devicetree
clk: sunxi: Add TCON channel1 clock
clk: sunxi: Add PLL3 clock
dt-bindings: clk: sun5i: add DRAM gates compatible
clk: sunxi: Use resource_size
clk: sunxi: Add sun6i/8i display support
clk: sunxi: mod1 clock should modify it's parent

+474 -13
+4
Documentation/devicetree/bindings/clock/sunxi.txt
··· 10 10 "allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4 11 11 "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31 12 12 "allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23 13 + "allwinner,sun4i-a10-pll3-clk" - for the video PLL clock on A10 13 14 "allwinner,sun9i-a80-pll4-clk" - for the peripheral PLLs on A80 14 15 "allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock 15 16 "allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock ··· 65 64 "allwinner,sun8i-h3-bus-gates-clk" - for the bus gates on H3 66 65 "allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80 67 66 "allwinner,sun4i-a10-dram-gates-clk" - for the DRAM gates on A10 67 + "allwinner,sun5i-a13-dram-gates-clk" - for the DRAM gates on A13 68 68 "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 69 69 "allwinner,sun4i-a10-mmc-clk" - for the MMC clock 70 70 "allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80 ··· 75 73 "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23 76 74 "allwinner,sun7i-a20-out-clk" - for the external output clocks 77 75 "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31 76 + "allwinner,sun4i-a10-tcon-ch1-clk" - for the TCON channel 1 clock on the A10 78 77 "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 79 78 "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13 80 79 "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31 ··· 84 81 "allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80 85 82 "allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80 86 83 "allwinner,sun4i-a10-ve-clk" - for the Video Engine clock 84 + "allwinner,sun6i-a31-display-clk" - for the display clocks 87 85 88 86 Required properties for all clocks: 89 87 - reg : shall be the control register address for the clock.
+2
drivers/clk/sunxi/Makefile
··· 11 11 obj-y += clk-a20-gmac.o 12 12 obj-y += clk-mod0.o 13 13 obj-y += clk-simple-gates.o 14 + obj-y += clk-sun4i-pll3.o 15 + obj-y += clk-sun4i-tcon-ch1.o 14 16 obj-y += clk-sun8i-bus-gates.o 15 17 obj-y += clk-sun8i-mbus.o 16 18 obj-y += clk-sun9i-core.o
+1 -1
drivers/clk/sunxi/clk-a10-mod1.c
··· 62 62 clk = clk_register_composite(NULL, clk_name, parents, i, 63 63 &mux->hw, &clk_mux_ops, 64 64 NULL, NULL, 65 - &gate->hw, &clk_gate_ops, 0); 65 + &gate->hw, &clk_gate_ops, CLK_SET_RATE_PARENT); 66 66 if (IS_ERR(clk)) 67 67 goto err_free_gate; 68 68
+98
drivers/clk/sunxi/clk-sun4i-pll3.c
··· 1 + /* 2 + * Copyright 2015 Maxime Ripard 3 + * 4 + * Maxime Ripard <maxime.ripard@free-electrons.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + */ 16 + 17 + #include <linux/clk-provider.h> 18 + #include <linux/of.h> 19 + #include <linux/of_address.h> 20 + #include <linux/slab.h> 21 + #include <linux/spinlock.h> 22 + 23 + #define SUN4I_A10_PLL3_GATE_BIT 31 24 + #define SUN4I_A10_PLL3_DIV_WIDTH 7 25 + #define SUN4I_A10_PLL3_DIV_SHIFT 0 26 + 27 + static DEFINE_SPINLOCK(sun4i_a10_pll3_lock); 28 + 29 + static void __init sun4i_a10_pll3_setup(struct device_node *node) 30 + { 31 + const char *clk_name = node->name, *parent; 32 + struct clk_multiplier *mult; 33 + struct clk_gate *gate; 34 + struct resource res; 35 + void __iomem *reg; 36 + struct clk *clk; 37 + int ret; 38 + 39 + of_property_read_string(node, "clock-output-names", &clk_name); 40 + parent = of_clk_get_parent_name(node, 0); 41 + 42 + reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 43 + if (IS_ERR(reg)) { 44 + pr_err("%s: Could not map the clock registers\n", clk_name); 45 + return; 46 + } 47 + 48 + gate = kzalloc(sizeof(*gate), GFP_KERNEL); 49 + if (!gate) 50 + goto err_unmap; 51 + 52 + gate->reg = reg; 53 + gate->bit_idx = SUN4I_A10_PLL3_GATE_BIT; 54 + gate->lock = &sun4i_a10_pll3_lock; 55 + 56 + mult = kzalloc(sizeof(*mult), GFP_KERNEL); 57 + if (!mult) 58 + goto err_free_gate; 59 + 60 + mult->reg = reg; 61 + mult->shift = SUN4I_A10_PLL3_DIV_SHIFT; 62 + mult->width = SUN4I_A10_PLL3_DIV_WIDTH; 63 + mult->lock = &sun4i_a10_pll3_lock; 64 + 65 + clk = clk_register_composite(NULL, clk_name, 66 + &parent, 1, 67 + NULL, NULL, 68 + &mult->hw, &clk_multiplier_ops, 69 + &gate->hw, &clk_gate_ops, 70 + 0); 71 + if (IS_ERR(clk)) { 72 + pr_err("%s: Couldn't register the clock\n", clk_name); 73 + goto err_free_mult; 74 + } 75 + 76 + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); 77 + if (ret) { 78 + pr_err("%s: Couldn't register DT provider\n", 79 + clk_name); 80 + goto err_clk_unregister; 81 + } 82 + 83 + return; 84 + 85 + err_clk_unregister: 86 + clk_unregister_composite(clk); 87 + err_free_mult: 88 + kfree(mult); 89 + err_free_gate: 90 + kfree(gate); 91 + err_unmap: 92 + iounmap(reg); 93 + of_address_to_resource(node, 0, &res); 94 + release_mem_region(res.start, resource_size(&res)); 95 + } 96 + 97 + CLK_OF_DECLARE(sun4i_a10_pll3, "allwinner,sun4i-a10-pll3-clk", 98 + sun4i_a10_pll3_setup);
+300
drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
··· 1 + /* 2 + * Copyright 2015 Maxime Ripard 3 + * 4 + * Maxime Ripard <maxime.ripard@free-electrons.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + */ 16 + 17 + #include <linux/clk-provider.h> 18 + #include <linux/of.h> 19 + #include <linux/of_address.h> 20 + #include <linux/slab.h> 21 + #include <linux/spinlock.h> 22 + 23 + #define TCON_CH1_SCLK2_PARENTS 4 24 + 25 + #define TCON_CH1_SCLK2_GATE_BIT BIT(31) 26 + #define TCON_CH1_SCLK2_MUX_MASK 3 27 + #define TCON_CH1_SCLK2_MUX_SHIFT 24 28 + #define TCON_CH1_SCLK2_DIV_MASK 0xf 29 + #define TCON_CH1_SCLK2_DIV_SHIFT 0 30 + 31 + #define TCON_CH1_SCLK1_GATE_BIT BIT(15) 32 + #define TCON_CH1_SCLK1_HALF_BIT BIT(11) 33 + 34 + struct tcon_ch1_clk { 35 + struct clk_hw hw; 36 + spinlock_t lock; 37 + void __iomem *reg; 38 + }; 39 + 40 + #define hw_to_tclk(hw) container_of(hw, struct tcon_ch1_clk, hw) 41 + 42 + static void tcon_ch1_disable(struct clk_hw *hw) 43 + { 44 + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 45 + unsigned long flags; 46 + u32 reg; 47 + 48 + spin_lock_irqsave(&tclk->lock, flags); 49 + reg = readl(tclk->reg); 50 + reg &= ~(TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT); 51 + writel(reg, tclk->reg); 52 + spin_unlock_irqrestore(&tclk->lock, flags); 53 + } 54 + 55 + static int tcon_ch1_enable(struct clk_hw *hw) 56 + { 57 + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 58 + unsigned long flags; 59 + u32 reg; 60 + 61 + spin_lock_irqsave(&tclk->lock, flags); 62 + reg = readl(tclk->reg); 63 + reg |= TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT; 64 + writel(reg, tclk->reg); 65 + spin_unlock_irqrestore(&tclk->lock, flags); 66 + 67 + return 0; 68 + } 69 + 70 + static int tcon_ch1_is_enabled(struct clk_hw *hw) 71 + { 72 + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 73 + u32 reg; 74 + 75 + reg = readl(tclk->reg); 76 + return reg & (TCON_CH1_SCLK2_GATE_BIT | TCON_CH1_SCLK1_GATE_BIT); 77 + } 78 + 79 + static u8 tcon_ch1_get_parent(struct clk_hw *hw) 80 + { 81 + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 82 + int num_parents = clk_hw_get_num_parents(hw); 83 + u32 reg; 84 + 85 + reg = readl(tclk->reg) >> TCON_CH1_SCLK2_MUX_SHIFT; 86 + reg &= reg >> TCON_CH1_SCLK2_MUX_MASK; 87 + 88 + if (reg >= num_parents) 89 + return -EINVAL; 90 + 91 + return reg; 92 + } 93 + 94 + static int tcon_ch1_set_parent(struct clk_hw *hw, u8 index) 95 + { 96 + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 97 + unsigned long flags; 98 + u32 reg; 99 + 100 + spin_lock_irqsave(&tclk->lock, flags); 101 + reg = readl(tclk->reg); 102 + reg &= ~(TCON_CH1_SCLK2_MUX_MASK << TCON_CH1_SCLK2_MUX_SHIFT); 103 + reg |= index << TCON_CH1_SCLK2_MUX_SHIFT; 104 + writel(reg, tclk->reg); 105 + spin_unlock_irqrestore(&tclk->lock, flags); 106 + 107 + return 0; 108 + }; 109 + 110 + static unsigned long tcon_ch1_calc_divider(unsigned long rate, 111 + unsigned long parent_rate, 112 + u8 *div, 113 + bool *half) 114 + { 115 + unsigned long best_rate = 0; 116 + u8 best_m = 0, m; 117 + bool is_double; 118 + 119 + for (m = 1; m < 16; m++) { 120 + u8 d; 121 + 122 + for (d = 1; d < 3; d++) { 123 + unsigned long tmp_rate; 124 + 125 + tmp_rate = parent_rate / m / d; 126 + 127 + if (tmp_rate > rate) 128 + continue; 129 + 130 + if (!best_rate || 131 + (rate - tmp_rate) < (rate - best_rate)) { 132 + best_rate = tmp_rate; 133 + best_m = m; 134 + is_double = d; 135 + } 136 + } 137 + } 138 + 139 + if (div && half) { 140 + *div = best_m; 141 + *half = is_double; 142 + } 143 + 144 + return best_rate; 145 + } 146 + 147 + static int tcon_ch1_determine_rate(struct clk_hw *hw, 148 + struct clk_rate_request *req) 149 + { 150 + long best_rate = -EINVAL; 151 + int i; 152 + 153 + for (i = 0; i < clk_hw_get_num_parents(hw); i++) { 154 + unsigned long parent_rate; 155 + unsigned long tmp_rate; 156 + struct clk_hw *parent; 157 + 158 + parent = clk_hw_get_parent_by_index(hw, i); 159 + if (!parent) 160 + continue; 161 + 162 + parent_rate = clk_hw_get_rate(parent); 163 + 164 + tmp_rate = tcon_ch1_calc_divider(req->rate, parent_rate, 165 + NULL, NULL); 166 + 167 + if (best_rate < 0 || 168 + (req->rate - tmp_rate) < (req->rate - best_rate)) { 169 + best_rate = tmp_rate; 170 + req->best_parent_rate = parent_rate; 171 + req->best_parent_hw = parent; 172 + } 173 + } 174 + 175 + if (best_rate < 0) 176 + return best_rate; 177 + 178 + req->rate = best_rate; 179 + return 0; 180 + } 181 + 182 + static unsigned long tcon_ch1_recalc_rate(struct clk_hw *hw, 183 + unsigned long parent_rate) 184 + { 185 + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 186 + u32 reg; 187 + 188 + reg = readl(tclk->reg); 189 + 190 + parent_rate /= (reg & TCON_CH1_SCLK2_DIV_MASK) + 1; 191 + 192 + if (reg & TCON_CH1_SCLK1_HALF_BIT) 193 + parent_rate /= 2; 194 + 195 + return parent_rate; 196 + } 197 + 198 + static int tcon_ch1_set_rate(struct clk_hw *hw, unsigned long rate, 199 + unsigned long parent_rate) 200 + { 201 + struct tcon_ch1_clk *tclk = hw_to_tclk(hw); 202 + unsigned long flags; 203 + bool half; 204 + u8 div_m; 205 + u32 reg; 206 + 207 + tcon_ch1_calc_divider(rate, parent_rate, &div_m, &half); 208 + 209 + spin_lock_irqsave(&tclk->lock, flags); 210 + reg = readl(tclk->reg); 211 + reg &= ~(TCON_CH1_SCLK2_DIV_MASK | TCON_CH1_SCLK1_HALF_BIT); 212 + reg |= (div_m - 1) & TCON_CH1_SCLK2_DIV_MASK; 213 + 214 + if (half) 215 + reg |= TCON_CH1_SCLK1_HALF_BIT; 216 + 217 + writel(reg, tclk->reg); 218 + spin_unlock_irqrestore(&tclk->lock, flags); 219 + 220 + return 0; 221 + } 222 + 223 + static const struct clk_ops tcon_ch1_ops = { 224 + .disable = tcon_ch1_disable, 225 + .enable = tcon_ch1_enable, 226 + .is_enabled = tcon_ch1_is_enabled, 227 + 228 + .get_parent = tcon_ch1_get_parent, 229 + .set_parent = tcon_ch1_set_parent, 230 + 231 + .determine_rate = tcon_ch1_determine_rate, 232 + .recalc_rate = tcon_ch1_recalc_rate, 233 + .set_rate = tcon_ch1_set_rate, 234 + }; 235 + 236 + static void __init tcon_ch1_setup(struct device_node *node) 237 + { 238 + const char *parents[TCON_CH1_SCLK2_PARENTS]; 239 + const char *clk_name = node->name; 240 + struct clk_init_data init; 241 + struct tcon_ch1_clk *tclk; 242 + struct resource res; 243 + struct clk *clk; 244 + void __iomem *reg; 245 + int ret; 246 + 247 + of_property_read_string(node, "clock-output-names", &clk_name); 248 + 249 + reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 250 + if (IS_ERR(reg)) { 251 + pr_err("%s: Could not map the clock registers\n", clk_name); 252 + return; 253 + } 254 + 255 + ret = of_clk_parent_fill(node, parents, TCON_CH1_SCLK2_PARENTS); 256 + if (ret != TCON_CH1_SCLK2_PARENTS) { 257 + pr_err("%s Could not retrieve the parents\n", clk_name); 258 + goto err_unmap; 259 + } 260 + 261 + tclk = kzalloc(sizeof(*tclk), GFP_KERNEL); 262 + if (!tclk) 263 + goto err_unmap; 264 + 265 + init.name = clk_name; 266 + init.ops = &tcon_ch1_ops; 267 + init.parent_names = parents; 268 + init.num_parents = TCON_CH1_SCLK2_PARENTS; 269 + init.flags = CLK_SET_RATE_PARENT; 270 + 271 + tclk->reg = reg; 272 + tclk->hw.init = &init; 273 + spin_lock_init(&tclk->lock); 274 + 275 + clk = clk_register(NULL, &tclk->hw); 276 + if (IS_ERR(clk)) { 277 + pr_err("%s: Couldn't register the clock\n", clk_name); 278 + goto err_free_data; 279 + } 280 + 281 + ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); 282 + if (ret) { 283 + pr_err("%s: Couldn't register our clock provider\n", clk_name); 284 + goto err_unregister_clk; 285 + } 286 + 287 + return; 288 + 289 + err_unregister_clk: 290 + clk_unregister(clk); 291 + err_free_data: 292 + kfree(tclk); 293 + err_unmap: 294 + iounmap(reg); 295 + of_address_to_resource(node, 0, &res); 296 + release_mem_region(res.start, resource_size(&res)); 297 + } 298 + 299 + CLK_OF_DECLARE(tcon_ch1, "allwinner,sun4i-a10-tcon-ch1-clk", 300 + tcon_ch1_setup);
+1 -1
drivers/clk/sunxi/clk-sun9i-mmc.c
··· 106 106 107 107 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 108 108 /* one clock/reset pair per word */ 109 - count = DIV_ROUND_UP((r->end - r->start + 1), SUN9I_MMC_WIDTH); 109 + count = DIV_ROUND_UP((resource_size(r)), SUN9I_MMC_WIDTH); 110 110 data->membase = devm_ioremap_resource(&pdev->dev, r); 111 111 if (IS_ERR(data->membase)) 112 112 return PTR_ERR(data->membase);
+68 -11
drivers/clk/sunxi/clk-sunxi.c
··· 523 523 .enable = 31, 524 524 .table = &sun4i_pll5_config, 525 525 .getter = sun4i_get_pll5_factors, 526 - .name = "pll5", 527 - }; 528 - 529 - static const struct factors_data sun4i_pll6_data __initconst = { 530 - .enable = 31, 531 - .table = &sun4i_pll5_config, 532 - .getter = sun4i_get_pll5_factors, 533 - .name = "pll6", 534 526 }; 535 527 536 528 static const struct factors_data sun6i_a31_pll6_data __initconst = { 537 529 .enable = 31, 538 530 .table = &sun6i_a31_pll6_config, 539 531 .getter = sun6i_a31_get_pll6_factors, 540 - .name = "pll6x2", 541 532 }; 542 533 543 534 static const struct factors_data sun5i_a13_ahb_data __initconst = { ··· 924 933 }; 925 934 926 935 static const struct divs_data pll6_divs_data __initconst = { 927 - .factors = &sun4i_pll6_data, 936 + .factors = &sun4i_pll5_data, 928 937 .ndivs = 4, 929 938 .div = { 930 939 { .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */ ··· 966 975 struct clk_gate *gate = NULL; 967 976 struct clk_fixed_factor *fix_factor; 968 977 struct clk_divider *divider; 978 + struct factors_data factors = *data->factors; 979 + char *derived_name = NULL; 969 980 void __iomem *reg; 970 981 int ndivs = SUNXI_DIVS_MAX_QTY, i = 0; 971 982 int flags, clkflags; ··· 976 983 if (data->ndivs) 977 984 ndivs = data->ndivs; 978 985 986 + /* Try to find a name for base factor clock */ 987 + for (i = 0; i < ndivs; i++) { 988 + if (data->div[i].self) { 989 + of_property_read_string_index(node, "clock-output-names", 990 + i, &factors.name); 991 + break; 992 + } 993 + } 994 + /* If we don't have a .self clk use the first output-name up to '_' */ 995 + if (factors.name == NULL) { 996 + char *endp; 997 + 998 + of_property_read_string_index(node, "clock-output-names", 999 + 0, &clk_name); 1000 + endp = strchr(clk_name, '_'); 1001 + if (endp) { 1002 + derived_name = kstrndup(clk_name, endp - clk_name, 1003 + GFP_KERNEL); 1004 + factors.name = derived_name; 1005 + } else { 1006 + factors.name = clk_name; 1007 + } 1008 + } 1009 + 979 1010 /* Set up factor clock that we will be dividing */ 980 - pclk = sunxi_factors_clk_setup(node, data->factors); 1011 + pclk = sunxi_factors_clk_setup(node, &factors); 981 1012 if (!pclk) 982 1013 return NULL; 1014 + 983 1015 parent = __clk_get_name(pclk); 1016 + kfree(derived_name); 984 1017 985 1018 reg = of_iomap(node, 0); 986 1019 if (!reg) { ··· 1146 1127 } 1147 1128 CLK_OF_DECLARE(sun6i_pll6, "allwinner,sun6i-a31-pll6-clk", 1148 1129 sun6i_pll6_clk_setup); 1130 + 1131 + /* 1132 + * sun6i display 1133 + * 1134 + * rate = parent_rate / (m + 1); 1135 + */ 1136 + static void sun6i_display_factors(struct factors_request *req) 1137 + { 1138 + u8 m; 1139 + 1140 + if (req->rate > req->parent_rate) 1141 + req->rate = req->parent_rate; 1142 + 1143 + m = DIV_ROUND_UP(req->parent_rate, req->rate); 1144 + 1145 + req->rate = req->parent_rate / m; 1146 + req->m = m - 1; 1147 + } 1148 + 1149 + static const struct clk_factors_config sun6i_display_config = { 1150 + .mshift = 0, 1151 + .mwidth = 4, 1152 + }; 1153 + 1154 + static const struct factors_data sun6i_display_data __initconst = { 1155 + .enable = 31, 1156 + .mux = 24, 1157 + .muxmask = BIT(2) | BIT(1) | BIT(0), 1158 + .table = &sun6i_display_config, 1159 + .getter = sun6i_display_factors, 1160 + }; 1161 + 1162 + static void __init sun6i_display_setup(struct device_node *node) 1163 + { 1164 + sunxi_factors_clk_setup(node, &sun6i_display_data); 1165 + } 1166 + CLK_OF_DECLARE(sun6i_display, "allwinner,sun6i-a31-display-clk", 1167 + sun6i_display_setup);