brintos

brintos / linux-shallow public Read only

0
0
Text · 4.1 KiB · a5ab27c Raw
158 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Freescale ALSA SoC Machine driver utility4//5// Author: Timur Tabi <timur@freescale.com>6//7// Copyright 2010 Freescale Semiconductor, Inc.8 9#include <linux/clk.h>10#include <linux/clk-provider.h>11#include <linux/module.h>12#include <linux/of_address.h>13#include <sound/soc.h>14 15#include "fsl_utils.h"16 17/**18 * fsl_asoc_get_dma_channel - determine the dma channel for a SSI node19 *20 * @ssi_np: pointer to the SSI device tree node21 * @name: name of the phandle pointing to the dma channel22 * @dai: ASoC DAI link pointer to be filled with platform_name23 * @dma_channel_id: dma channel id to be returned24 * @dma_id: dma id to be returned25 *26 * This function determines the dma and channel id for given SSI node.  It27 * also discovers the platform_name for the ASoC DAI link.28 */29int fsl_asoc_get_dma_channel(struct device_node *ssi_np,30			     const char *name,31			     struct snd_soc_dai_link *dai,32			     unsigned int *dma_channel_id,33			     unsigned int *dma_id)34{35	struct resource res;36	struct device_node *dma_channel_np, *dma_np;37	const __be32 *iprop;38	int ret;39 40	dma_channel_np = of_parse_phandle(ssi_np, name, 0);41	if (!dma_channel_np)42		return -EINVAL;43 44	if (!of_device_is_compatible(dma_channel_np, "fsl,ssi-dma-channel")) {45		of_node_put(dma_channel_np);46		return -EINVAL;47	}48 49	/* Determine the dev_name for the device_node.  This code mimics the50	 * behavior of of_device_make_bus_id(). We need this because ASoC uses51	 * the dev_name() of the device to match the platform (DMA) device with52	 * the CPU (SSI) device.  It's all ugly and hackish, but it works (for53	 * now).54	 *55	 * dai->platform name should already point to an allocated buffer.56	 */57	ret = of_address_to_resource(dma_channel_np, 0, &res);58	if (ret) {59		of_node_put(dma_channel_np);60		return ret;61	}62	snprintf((char *)dai->platforms->name, DAI_NAME_SIZE, "%llx.%pOFn",63		 (unsigned long long) res.start, dma_channel_np);64 65	iprop = of_get_property(dma_channel_np, "cell-index", NULL);66	if (!iprop) {67		of_node_put(dma_channel_np);68		return -EINVAL;69	}70	*dma_channel_id = be32_to_cpup(iprop);71 72	dma_np = of_get_parent(dma_channel_np);73	iprop = of_get_property(dma_np, "cell-index", NULL);74	if (!iprop) {75		of_node_put(dma_np);76		of_node_put(dma_channel_np);77		return -EINVAL;78	}79	*dma_id = be32_to_cpup(iprop);80 81	of_node_put(dma_np);82	of_node_put(dma_channel_np);83 84	return 0;85}86EXPORT_SYMBOL(fsl_asoc_get_dma_channel);87 88/**89 * fsl_asoc_get_pll_clocks - get two PLL clock source90 *91 * @dev: device pointer92 * @pll8k_clk: PLL clock pointer for 8kHz93 * @pll11k_clk: PLL clock pointer for 11kHz94 *95 * This function get two PLL clock source96 */97void fsl_asoc_get_pll_clocks(struct device *dev, struct clk **pll8k_clk,98			     struct clk **pll11k_clk)99{100	*pll8k_clk = devm_clk_get(dev, "pll8k");101	if (IS_ERR(*pll8k_clk))102		*pll8k_clk = NULL;103 104	*pll11k_clk = devm_clk_get(dev, "pll11k");105	if (IS_ERR(*pll11k_clk))106		*pll11k_clk = NULL;107}108EXPORT_SYMBOL(fsl_asoc_get_pll_clocks);109 110/**111 * fsl_asoc_reparent_pll_clocks - set clock parent if necessary112 *113 * @dev: device pointer114 * @clk: root clock pointer115 * @pll8k_clk: PLL clock pointer for 8kHz116 * @pll11k_clk: PLL clock pointer for 11kHz117 * @ratio: target requency for root clock118 *119 * This function set root clock parent according to the target ratio120 */121void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk,122				  struct clk *pll8k_clk,123				  struct clk *pll11k_clk, u64 ratio)124{125	struct clk *p, *pll = NULL, *npll = NULL;126	bool reparent = false;127	int ret;128 129	if (!clk || !pll8k_clk || !pll11k_clk)130		return;131 132	p = clk;133	while (p && pll8k_clk && pll11k_clk) {134		struct clk *pp = clk_get_parent(p);135 136		if (clk_is_match(pp, pll8k_clk) ||137		    clk_is_match(pp, pll11k_clk)) {138			pll = pp;139			break;140		}141		p = pp;142	}143 144	npll = (do_div(ratio, 8000) ? pll11k_clk : pll8k_clk);145	reparent = (pll && !clk_is_match(pll, npll));146 147	if (reparent) {148		ret = clk_set_parent(p, npll);149		if (ret < 0)150			dev_warn(dev, "failed to set parent:%d\n", ret);151	}152}153EXPORT_SYMBOL(fsl_asoc_reparent_pll_clocks);154 155MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");156MODULE_DESCRIPTION("Freescale ASoC utility code");157MODULE_LICENSE("GPL v2");158