xref: /netbsd-src/sys/arch/arm/sunxi/sunxi_ccu_prediv.c (revision 69b44ac77b4b38950411c0a50726267e4b1e5fc2)
1*69b44ac7Sjmcneill /* $NetBSD: sunxi_ccu_prediv.c,v 1.3 2017/08/25 00:07:03 jmcneill Exp $ */
211d415cdSjmcneill 
311d415cdSjmcneill /*-
411d415cdSjmcneill  * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca>
511d415cdSjmcneill  * All rights reserved.
611d415cdSjmcneill  *
711d415cdSjmcneill  * Redistribution and use in source and binary forms, with or without
811d415cdSjmcneill  * modification, are permitted provided that the following conditions
911d415cdSjmcneill  * are met:
1011d415cdSjmcneill  * 1. Redistributions of source code must retain the above copyright
1111d415cdSjmcneill  *    notice, this list of conditions and the following disclaimer.
1211d415cdSjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
1311d415cdSjmcneill  *    notice, this list of conditions and the following disclaimer in the
1411d415cdSjmcneill  *    documentation and/or other materials provided with the distribution.
1511d415cdSjmcneill  *
1611d415cdSjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1711d415cdSjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1811d415cdSjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1911d415cdSjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2011d415cdSjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2111d415cdSjmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2211d415cdSjmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2311d415cdSjmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2411d415cdSjmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2511d415cdSjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2611d415cdSjmcneill  * SUCH DAMAGE.
2711d415cdSjmcneill  */
2811d415cdSjmcneill 
2911d415cdSjmcneill #include <sys/cdefs.h>
30*69b44ac7Sjmcneill __KERNEL_RCSID(0, "$NetBSD: sunxi_ccu_prediv.c,v 1.3 2017/08/25 00:07:03 jmcneill Exp $");
3111d415cdSjmcneill 
3211d415cdSjmcneill #include <sys/param.h>
3311d415cdSjmcneill #include <sys/bus.h>
3411d415cdSjmcneill 
3511d415cdSjmcneill #include <dev/clk/clk_backend.h>
3611d415cdSjmcneill 
3711d415cdSjmcneill #include <arm/sunxi/sunxi_ccu.h>
3811d415cdSjmcneill 
3911d415cdSjmcneill u_int
sunxi_ccu_prediv_get_rate(struct sunxi_ccu_softc * sc,struct sunxi_ccu_clk * clk)4011d415cdSjmcneill sunxi_ccu_prediv_get_rate(struct sunxi_ccu_softc *sc,
4111d415cdSjmcneill     struct sunxi_ccu_clk *clk)
4211d415cdSjmcneill {
4311d415cdSjmcneill 	struct sunxi_ccu_prediv *prediv = &clk->u.prediv;
4411d415cdSjmcneill 	struct clk *clkp, *clkp_parent;
4511d415cdSjmcneill 	u_int rate, pre, div, sel;
4611d415cdSjmcneill 	uint32_t val;
4711d415cdSjmcneill 
4811d415cdSjmcneill 	KASSERT(clk->type == SUNXI_CCU_PREDIV);
4911d415cdSjmcneill 
5011d415cdSjmcneill 	clkp = &clk->base;
5111d415cdSjmcneill 	clkp_parent = clk_get_parent(clkp);
5211d415cdSjmcneill 	if (clkp_parent == NULL)
5311d415cdSjmcneill 		return 0;
5411d415cdSjmcneill 
5511d415cdSjmcneill 	rate = clk_get_rate(clkp_parent);
5611d415cdSjmcneill 	if (rate == 0)
5711d415cdSjmcneill 		return 0;
5811d415cdSjmcneill 
5911d415cdSjmcneill 	val = CCU_READ(sc, prediv->reg);
601e6185e4Sjmcneill 	if (prediv->prediv)
6111d415cdSjmcneill 		pre = __SHIFTOUT(val, prediv->prediv);
621e6185e4Sjmcneill 	else
631e6185e4Sjmcneill 		pre = 0;
641e6185e4Sjmcneill 	if (prediv->div)
6511d415cdSjmcneill 		div = __SHIFTOUT(val, prediv->div);
661e6185e4Sjmcneill 	else
671e6185e4Sjmcneill 		div = 0;
6811d415cdSjmcneill 	sel = __SHIFTOUT(val, prediv->sel);
6911d415cdSjmcneill 
7011d415cdSjmcneill 	if (prediv->flags & SUNXI_CCU_PREDIV_POWER_OF_TWO)
7111d415cdSjmcneill 		div = 1 << div;
7211d415cdSjmcneill 	else
7311d415cdSjmcneill 		div++;
7411d415cdSjmcneill 
75*69b44ac7Sjmcneill 	if (prediv->prediv_fixed)
76*69b44ac7Sjmcneill 		pre = prediv->prediv_fixed;
77*69b44ac7Sjmcneill 	else
7811d415cdSjmcneill 		pre++;
7911d415cdSjmcneill 
801e6185e4Sjmcneill 	if (prediv->flags & SUNXI_CCU_PREDIV_DIVIDE_BY_TWO)
811e6185e4Sjmcneill 		pre *= 2;
821e6185e4Sjmcneill 
8311d415cdSjmcneill 	if (prediv->prediv_sel & __BIT(sel))
8411d415cdSjmcneill 		return rate / pre / div;
8511d415cdSjmcneill 	else
8611d415cdSjmcneill 		return rate / div;
8711d415cdSjmcneill }
8811d415cdSjmcneill 
8911d415cdSjmcneill int
sunxi_ccu_prediv_set_rate(struct sunxi_ccu_softc * sc,struct sunxi_ccu_clk * clk,u_int new_rate)9011d415cdSjmcneill sunxi_ccu_prediv_set_rate(struct sunxi_ccu_softc *sc,
9111d415cdSjmcneill     struct sunxi_ccu_clk *clk, u_int new_rate)
9211d415cdSjmcneill {
9311d415cdSjmcneill 	return EINVAL;
9411d415cdSjmcneill }
9511d415cdSjmcneill 
9611d415cdSjmcneill int
sunxi_ccu_prediv_set_parent(struct sunxi_ccu_softc * sc,struct sunxi_ccu_clk * clk,const char * name)9711d415cdSjmcneill sunxi_ccu_prediv_set_parent(struct sunxi_ccu_softc *sc,
9811d415cdSjmcneill     struct sunxi_ccu_clk *clk, const char *name)
9911d415cdSjmcneill {
10011d415cdSjmcneill 	struct sunxi_ccu_prediv *prediv = &clk->u.prediv;
10111d415cdSjmcneill 	uint32_t val;
10211d415cdSjmcneill 	u_int index;
10311d415cdSjmcneill 
10411d415cdSjmcneill 	KASSERT(clk->type == SUNXI_CCU_PREDIV);
10511d415cdSjmcneill 
10611d415cdSjmcneill 	if (prediv->sel == 0)
10711d415cdSjmcneill 		return ENODEV;
10811d415cdSjmcneill 
10911d415cdSjmcneill 	for (index = 0; index < prediv->nparents; index++) {
11011d415cdSjmcneill 		if (prediv->parents[index] != NULL &&
11111d415cdSjmcneill 		    strcmp(prediv->parents[index], name) == 0)
11211d415cdSjmcneill 			break;
11311d415cdSjmcneill 	}
11411d415cdSjmcneill 	if (index == prediv->nparents)
11511d415cdSjmcneill 		return EINVAL;
11611d415cdSjmcneill 
11711d415cdSjmcneill 	val = CCU_READ(sc, prediv->reg);
11811d415cdSjmcneill 	val &= ~prediv->sel;
11911d415cdSjmcneill 	val |= __SHIFTIN(index, prediv->sel);
12011d415cdSjmcneill 	CCU_WRITE(sc, prediv->reg, val);
12111d415cdSjmcneill 
12211d415cdSjmcneill 	return 0;
12311d415cdSjmcneill }
12411d415cdSjmcneill 
12511d415cdSjmcneill const char *
sunxi_ccu_prediv_get_parent(struct sunxi_ccu_softc * sc,struct sunxi_ccu_clk * clk)12611d415cdSjmcneill sunxi_ccu_prediv_get_parent(struct sunxi_ccu_softc *sc,
12711d415cdSjmcneill     struct sunxi_ccu_clk *clk)
12811d415cdSjmcneill {
12911d415cdSjmcneill 	struct sunxi_ccu_prediv *prediv = &clk->u.prediv;
13011d415cdSjmcneill 	u_int index;
13111d415cdSjmcneill 	uint32_t val;
13211d415cdSjmcneill 
13311d415cdSjmcneill 	KASSERT(clk->type == SUNXI_CCU_PREDIV);
13411d415cdSjmcneill 
13511d415cdSjmcneill 	val = CCU_READ(sc, prediv->reg);
13611d415cdSjmcneill 	index = __SHIFTOUT(val, prediv->sel);
13711d415cdSjmcneill 
13811d415cdSjmcneill 	return prediv->parents[index];
13911d415cdSjmcneill }
140