Commit 7cfefab6 authored by Jerome Brunet's avatar Jerome Brunet
Browse files

clk: meson: axg-audio: add g12a reset support



On the g12a, the register space dedicated to the audio clock also
provides some resets. Let the clock controller register a reset
provider as well for this SoC family.

the axg SoC family does not appear to provide this feature.

Reviewed-by: default avatarNeil Armstrong <narmstrong@baylibre.com>
Signed-off-by: default avatarJerome Brunet <jbrunet@baylibre.com>
parent 1d7cedbd
Loading
Loading
Loading
Loading
+105 −2
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>

#include "axg-audio.h"
@@ -918,6 +919,84 @@ static int devm_clk_get_enable(struct device *dev, char *id)
	return 0;
}

struct axg_audio_reset_data {
	struct reset_controller_dev rstc;
	struct regmap *map;
	unsigned int offset;
};

static void axg_audio_reset_reg_and_bit(struct axg_audio_reset_data *rst,
					unsigned long id,
					unsigned int *reg,
					unsigned int *bit)
{
	unsigned int stride = regmap_get_reg_stride(rst->map);

	*reg = (id / (stride * BITS_PER_BYTE)) * stride;
	*reg += rst->offset;
	*bit = id % (stride * BITS_PER_BYTE);
}

static int axg_audio_reset_update(struct reset_controller_dev *rcdev,
				unsigned long id, bool assert)
{
	struct axg_audio_reset_data *rst =
		container_of(rcdev, struct axg_audio_reset_data, rstc);
	unsigned int offset, bit;

	axg_audio_reset_reg_and_bit(rst, id, &offset, &bit);

	regmap_update_bits(rst->map, offset, BIT(bit),
			assert ? BIT(bit) : 0);

	return 0;
}

static int axg_audio_reset_status(struct reset_controller_dev *rcdev,
				unsigned long id)
{
	struct axg_audio_reset_data *rst =
		container_of(rcdev, struct axg_audio_reset_data, rstc);
	unsigned int val, offset, bit;

	axg_audio_reset_reg_and_bit(rst, id, &offset, &bit);

	regmap_read(rst->map, offset, &val);

	return !!(val & BIT(bit));
}

static int axg_audio_reset_assert(struct reset_controller_dev *rcdev,
				unsigned long id)
{
	return axg_audio_reset_update(rcdev, id, true);
}

static int axg_audio_reset_deassert(struct reset_controller_dev *rcdev,
				unsigned long id)
{
	return axg_audio_reset_update(rcdev, id, false);
}

static int axg_audio_reset_toggle(struct reset_controller_dev *rcdev,
				unsigned long id)
{
	int ret;

	ret = axg_audio_reset_assert(rcdev, id);
	if (ret)
		return ret;

	return axg_audio_reset_deassert(rcdev, id);
}

static const struct reset_control_ops axg_audio_rstc_ops = {
	.assert = axg_audio_reset_assert,
	.deassert = axg_audio_reset_deassert,
	.reset = axg_audio_reset_toggle,
	.status = axg_audio_reset_status,
};

static const struct regmap_config axg_audio_regmap_cfg = {
	.reg_bits	= 32,
	.val_bits	= 32,
@@ -927,12 +1006,15 @@ static const struct regmap_config axg_audio_regmap_cfg = {

struct audioclk_data {
	struct clk_hw_onecell_data *hw_onecell_data;
	unsigned int reset_offset;
	unsigned int reset_num;
};

static int axg_audio_clkc_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	const struct audioclk_data *data;
	struct axg_audio_reset_data *rst;
	struct regmap *map;
	struct resource *res;
	void __iomem *regs;
@@ -984,8 +1066,27 @@ static int axg_audio_clkc_probe(struct platform_device *pdev)
		}
	}

	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
					data->hw_onecell_data);
	if (ret)
		return ret;

	/* Stop here if there is no reset */
	if (!data->reset_num)
		return 0;

	rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL);
	if (!rst)
		return -ENOMEM;

	rst->map = map;
	rst->offset = data->reset_offset;
	rst->rstc.nr_resets = data->reset_num;
	rst->rstc.ops = &axg_audio_rstc_ops;
	rst->rstc.of_node = dev->of_node;
	rst->rstc.owner = THIS_MODULE;

	return devm_reset_controller_register(dev, &rst->rstc);
}

static const struct audioclk_data axg_audioclk_data = {
@@ -994,6 +1095,8 @@ static const struct audioclk_data axg_audioclk_data = {

static const struct audioclk_data g12a_audioclk_data = {
	.hw_onecell_data = &g12a_audio_hw_onecell_data,
	.reset_offset = AUDIO_SW_RESET,
	.reset_num = 26,
};

static const struct of_device_id clkc_match_table[] = {
+1 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#define AUDIO_MCLK_F_CTRL	0x018
#define AUDIO_MST_PAD_CTRL0	0x01c
#define AUDIO_MST_PAD_CTRL1	0x020
#define AUDIO_SW_RESET		0x024
#define AUDIO_MST_A_SCLK_CTRL0	0x040
#define AUDIO_MST_A_SCLK_CTRL1	0x044
#define AUDIO_MST_B_SCLK_CTRL0	0x048