Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit adb50e3f authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "soc: soundwire: Update bus clock frequency based on usecase"

parents 923f0c87 ae5c363a
Loading
Loading
Loading
Loading
+8 −1
Original line number Original line Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-License-Identifier: GPL-2.0-only */
/*
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */
 */


#ifndef _LINUX_SOUNDWIRE_H
#ifndef _LINUX_SOUNDWIRE_H
@@ -10,6 +10,13 @@
#include <linux/mod_devicetable.h>
#include <linux/mod_devicetable.h>
#include <linux/irqdomain.h>
#include <linux/irqdomain.h>


#define SWR_CLK_RATE_0P6MHZ       600000
#define SWR_CLK_RATE_1P2MHZ      1200000
#define SWR_CLK_RATE_2P4MHZ      2400000
#define SWR_CLK_RATE_4P8MHZ      4800000
#define SWR_CLK_RATE_9P6MHZ      9600000
#define SWR_CLK_RATE_11P2896MHZ  1128960

extern struct bus_type soundwire_type;
extern struct bus_type soundwire_type;


/* Soundwire supports max. of 8 channels per port */
/* Soundwire supports max. of 8 channels per port */
+2 −1
Original line number Original line Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-License-Identifier: GPL-2.0-only */
/*
/*
 * Copyright (c) 2015, 2017-2019 The Linux Foundation. All rights reserved.
 * Copyright (c) 2015, 2017-2020 The Linux Foundation. All rights reserved.
 */
 */


#ifndef _LINUX_SWR_WCD_H
#ifndef _LINUX_SWR_WCD_H
@@ -32,6 +32,7 @@ struct swr_mstr_port {
};
};


#define MCLK_FREQ		9600000
#define MCLK_FREQ		9600000
#define MCLK_FREQ_LP		600000
#define MCLK_FREQ_NATIVE	11289600
#define MCLK_FREQ_NATIVE	11289600


#if (IS_ENABLED(CONFIG_SOUNDWIRE_WCD_CTRL) || \
#if (IS_ENABLED(CONFIG_SOUNDWIRE_WCD_CTRL) || \
+110 −12
Original line number Original line Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-License-Identifier: GPL-2.0-only
/*
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */
 */


#include <linux/irq.h>
#include <linux/irq.h>
@@ -25,6 +25,8 @@
#include "swrm_registers.h"
#include "swrm_registers.h"
#include "swr-mstr-ctrl.h"
#include "swr-mstr-ctrl.h"


#define SWR_NUM_PORTS    4 /* TODO - Get this info from DT */

#define SWRM_FRAME_SYNC_SEL    4000 /* 4KHz */
#define SWRM_FRAME_SYNC_SEL    4000 /* 4KHz */
#define SWRM_FRAME_SYNC_SEL_NATIVE 3675 /* 3.675KHz */
#define SWRM_FRAME_SYNC_SEL_NATIVE 3675 /* 3.675KHz */
#define SWRM_SYSTEM_RESUME_TIMEOUT_MS 700
#define SWRM_SYSTEM_RESUME_TIMEOUT_MS 700
@@ -94,6 +96,42 @@ static void swrm_unlock_sleep(struct swr_mstr_ctrl *swrm);
static u32 swr_master_read(struct swr_mstr_ctrl *swrm, unsigned int reg_addr);
static u32 swr_master_read(struct swr_mstr_ctrl *swrm, unsigned int reg_addr);
static void swr_master_write(struct swr_mstr_ctrl *swrm, u16 reg_addr, u32 val);
static void swr_master_write(struct swr_mstr_ctrl *swrm, u16 reg_addr, u32 val);



static u8 swrm_get_clk_div(int mclk_freq, int bus_clk_freq)
{
	int clk_div = 0;
	u8 div_val = 0;

	if (!mclk_freq || !bus_clk_freq)
		return 0;

	clk_div = (mclk_freq / bus_clk_freq);

	switch (clk_div) {
	case 32:
		div_val = 5;
		break;
	case 16:
		div_val = 4;
		break;
	case 8:
		div_val = 3;
		break;
	case 4:
		div_val = 2;
		break;
	case 2:
		div_val = 1;
		break;
	case 1:
	default:
		div_val = 0;
		break;
	}

	return div_val;
}

static bool swrm_is_msm_variant(int val)
static bool swrm_is_msm_variant(int val)
{
{
	return (val == SWRM_VERSION_1_3);
	return (val == SWRM_VERSION_1_3);
@@ -955,6 +993,49 @@ static bool swrm_remove_from_group(struct swr_master *master)
	return is_removed;
	return is_removed;
}
}


int swrm_get_clk_div_rate(int mclk_freq, int bus_clk_freq)
{
	if (!bus_clk_freq)
		return mclk_freq;

	if (mclk_freq == SWR_CLK_RATE_9P6MHZ) {
		if (bus_clk_freq <= SWR_CLK_RATE_0P6MHZ)
			bus_clk_freq = SWR_CLK_RATE_0P6MHZ;
		else if (bus_clk_freq <= SWR_CLK_RATE_1P2MHZ)
			bus_clk_freq = SWR_CLK_RATE_1P2MHZ;
		else if (bus_clk_freq <= SWR_CLK_RATE_2P4MHZ)
			bus_clk_freq = SWR_CLK_RATE_2P4MHZ;
		else if(bus_clk_freq <= SWR_CLK_RATE_4P8MHZ)
			bus_clk_freq = SWR_CLK_RATE_4P8MHZ;
		else if(bus_clk_freq <= SWR_CLK_RATE_9P6MHZ)
			bus_clk_freq = SWR_CLK_RATE_9P6MHZ;
	} else if (mclk_freq == SWR_CLK_RATE_11P2896MHZ)
		bus_clk_freq = SWR_CLK_RATE_11P2896MHZ;

	return bus_clk_freq;
}

static int swrm_update_bus_clk(struct swr_mstr_ctrl *swrm)
{
	int ret = 0;
	int agg_clk = 0;
	int i;

	for (i = 0; i < SWR_MSTR_PORT_LEN; i++)
		agg_clk += swrm->mport_cfg[i].ch_rate;

	if (agg_clk)
		swrm->bus_clk = swrm_get_clk_div_rate(swrm->mclk_freq,
							agg_clk);
	else
		swrm->bus_clk = swrm->mclk_freq;

	dev_dbg(swrm->dev, "%s: all_port_clk: %d, bus_clk: %d\n",
		__func__, agg_clk, swrm->bus_clk);

	return ret;
}

static void swrm_disable_ports(struct swr_master *master,
static void swrm_disable_ports(struct swr_master *master,
					     u8 bank)
					     u8 bank)
{
{
@@ -1221,13 +1302,15 @@ static void swrm_apply_port_config(struct swr_master *master)
static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable)
static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable)
{
{
	u8 bank;
	u8 bank;
	u32 value, n_row, n_col;
	u32 value = 0, n_row = 0, n_col = 0;
	u32 row = 0, col = 0;
	u32 row = 0, col = 0;
	int bus_clk_div_factor;
	int ret;
	int ret;
	u8 ssp_period = 0;
	u8 ssp_period = 0;
	struct swr_mstr_ctrl *swrm = swr_get_ctrl_data(master);
	struct swr_mstr_ctrl *swrm = swr_get_ctrl_data(master);
	int mask = (SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK |
	int mask = (SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK |
		    SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK |
		    SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK |
		    SWRM_MCP_FRAME_CTRL_BANK_CLK_DIV_VALUE_BMSK |
		    SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_BMSK);
		    SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_BMSK);
	u8 inactive_bank;
	u8 inactive_bank;
	int frame_sync = SWRM_FRAME_SYNC_SEL;
	int frame_sync = SWRM_FRAME_SYNC_SEL;
@@ -1288,13 +1371,17 @@ static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable)
		clear_bit(DISABLE_PENDING, &swrm->port_req_pending);
		clear_bit(DISABLE_PENDING, &swrm->port_req_pending);
		swrm_disable_ports(master, bank);
		swrm_disable_ports(master, bank);
	}
	}
	dev_dbg(swrm->dev, "%s: enable: %d, cfg_devs: %d\n",
	dev_dbg(swrm->dev, "%s: enable: %d, cfg_devs: %d freq %d\n",
		__func__, enable, swrm->num_cfg_devs);
		__func__, enable, swrm->num_cfg_devs, swrm->mclk_freq);


	if (enable) {
	if (enable) {
		/* set col = 16 */
		/* set col = 16 */
		n_col = SWR_MAX_COL;
		n_col = SWR_MAX_COL;
		col = SWRM_COL_16;
		col = SWRM_COL_16;
		if (swrm->bus_clk == MCLK_FREQ_LP) {
			n_col = SWR_MIN_COL;
			col = SWRM_COL_02;
		}
	} else {
	} else {
		/*
		/*
		 * Do not change to col = 2 if there are still active ports
		 * Do not change to col = 2 if there are still active ports
@@ -1309,25 +1396,26 @@ static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable)
	}
	}
	/* Use default 50 * x, frame shape. Change based on mclk */
	/* Use default 50 * x, frame shape. Change based on mclk */
	if (swrm->mclk_freq == MCLK_FREQ_NATIVE) {
	if (swrm->mclk_freq == MCLK_FREQ_NATIVE) {
		dev_dbg(swrm->dev, "setting 64 x %d frameshape\n",
		dev_dbg(swrm->dev, "setting 64 x %d frameshape\n", col);
			n_col ? 16 : 2);
		n_row = SWR_ROW_64;
		n_row = SWR_ROW_64;
		row = SWRM_ROW_64;
		row = SWRM_ROW_64;
		frame_sync = SWRM_FRAME_SYNC_SEL_NATIVE;
		frame_sync = SWRM_FRAME_SYNC_SEL_NATIVE;
	} else {
	} else {
		dev_dbg(swrm->dev, "setting 50 x %d frameshape\n",
		dev_dbg(swrm->dev, "setting 50 x %d frameshape\n", col);
			n_col ? 16 : 2);
		n_row = SWR_ROW_50;
		n_row = SWR_ROW_50;
		row = SWRM_ROW_50;
		row = SWRM_ROW_50;
		frame_sync = SWRM_FRAME_SYNC_SEL;
		frame_sync = SWRM_FRAME_SYNC_SEL;
	}
	}
	ssp_period = swrm_get_ssp_period(swrm, row, col, frame_sync);
	ssp_period = swrm_get_ssp_period(swrm, row, col, frame_sync);
	dev_dbg(swrm->dev, "%s: ssp_period: %d\n", __func__, ssp_period);
	bus_clk_div_factor = swrm_get_clk_div(swrm->mclk_freq, swrm->bus_clk);

	dev_dbg(swrm->dev, "%s: ssp_period: %d, bus_clk_div:%d \n", __func__,
					ssp_period, bus_clk_div_factor);
	value = swr_master_read(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank));
	value = swr_master_read(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank));
	value &= (~mask);
	value &= (~mask);
	value |= ((n_row << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT) |
	value |= ((n_row << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT) |
		  (n_col << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT) |
		  (n_col << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT) |
		  (bus_clk_div_factor <<
			SWRM_MCP_FRAME_CTRL_BANK_CLK_DIV_VALUE_SHFT) |
		  ((ssp_period - 1) << SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_SHFT));
		  ((ssp_period - 1) << SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_SHFT));
	swr_master_write(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank), value);
	swr_master_write(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank), value);


@@ -1431,6 +1519,11 @@ static int swrm_connect_port(struct swr_master *master,
		mport->port_en = true;
		mport->port_en = true;
		mport->req_ch |= mstr_ch_msk;
		mport->req_ch |= mstr_ch_msk;
		master->port_en_mask |= (1 << mstr_port_id);
		master->port_en_mask |= (1 << mstr_port_id);
		if (swrm->clk_stop_mode0_supp &&
			(mport->ch_rate < portinfo->ch_rate[i])) {
			mport->ch_rate = portinfo->ch_rate[i];
			swrm_update_bus_clk(swrm);
		}
	}
	}
	master->num_port += portinfo->num_port;
	master->num_port += portinfo->num_port;
	set_bit(ENABLE_PENDING, &swrm->port_req_pending);
	set_bit(ENABLE_PENDING, &swrm->port_req_pending);
@@ -1493,6 +1586,10 @@ static int swrm_disconnect_port(struct swr_master *master,
		}
		}
		port_req->req_ch &= ~portinfo->ch_en[i];
		port_req->req_ch &= ~portinfo->ch_en[i];
		mport->req_ch &= ~mstr_ch_mask;
		mport->req_ch &= ~mstr_ch_mask;
		if (swrm->clk_stop_mode0_supp && !mport->req_ch) {
			mport->ch_rate = 0;
			swrm_update_bus_clk(swrm);
		}
	}
	}
	master->num_port -= portinfo->num_port;
	master->num_port -= portinfo->num_port;
	set_bit(DISABLE_PENDING, &swrm->port_req_pending);
	set_bit(DISABLE_PENDING, &swrm->port_req_pending);
@@ -2402,9 +2499,10 @@ static int swrm_probe(struct platform_device *pdev)
		dev_dbg(&pdev->dev, "%s: Looking up %s property failed\n",
		dev_dbg(&pdev->dev, "%s: Looking up %s property failed\n",
			__func__, "qcom,swr-num-dev");
			__func__, "qcom,swr-num-dev");
	} else {
	} else {
		if (swrm->num_dev > SWR_MAX_SLAVE_DEVICES) {
		if (swrm->num_dev > SWRM_NUM_AUTO_ENUM_SLAVES) {
			dev_err(&pdev->dev, "%s: num_dev %d > max limit %d\n",
			dev_err(&pdev->dev, "%s: num_dev %d > max limit %d\n",
				__func__, swrm->num_dev, SWR_MAX_SLAVE_DEVICES);
				__func__, swrm->num_dev,
				SWRM_NUM_AUTO_ENUM_SLAVES);
			ret = -EINVAL;
			ret = -EINVAL;
			goto err_pdata_fail;
			goto err_pdata_fail;
		}
		}
+4 −3
Original line number Original line Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-License-Identifier: GPL-2.0-only */
/*
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */
 */


#ifndef _SWR_WCD_CTRL_H
#ifndef _SWR_WCD_CTRL_H
@@ -26,6 +26,7 @@
#define SWR_ROW_48		0
#define SWR_ROW_48		0
#define SWR_ROW_50		1
#define SWR_ROW_50		1
#define SWR_ROW_64		3
#define SWR_ROW_64		3
#define SWR_COL_04		1 /* Cols = 4 */
#define SWR_MAX_COL		7 /* Cols = 16 */
#define SWR_MAX_COL		7 /* Cols = 16 */
#define SWR_MIN_COL		0 /* Cols = 2 */
#define SWR_MIN_COL		0 /* Cols = 2 */


@@ -42,7 +43,7 @@


#define SWR_MAX_CH_PER_PORT 8
#define SWR_MAX_CH_PER_PORT 8


#define SWR_MAX_SLAVE_DEVICES 11
#define SWRM_NUM_AUTO_ENUM_SLAVES    6


enum {
enum {
	SWR_MSTR_PAUSE,
	SWR_MSTR_PAUSE,
@@ -81,7 +82,6 @@ struct swrm_mports {
	bool port_en;
	bool port_en;
	u8 ch_en;
	u8 ch_en;
	u8 req_ch;
	u8 req_ch;
	u8 ch_rate;
	u8 offset1;
	u8 offset1;
	u8 offset2;
	u8 offset2;
	u8 sinterval;
	u8 sinterval;
@@ -91,6 +91,7 @@ struct swrm_mports {
	u8 blk_pack_mode;
	u8 blk_pack_mode;
	u8 word_length;
	u8 word_length;
	u8 lane_ctrl;
	u8 lane_ctrl;
	u32 ch_rate;
};
};


struct swrm_port_type {
struct swrm_port_type {