soundwire updates for v5.4-rc1
This includes DT support thanks to Srini and more work done by Intel (Pierre) on improving cadence and intel support. Details: - Add DT bindings and DT support in core - Add debugfs support for soundwire properties - Improvements on streaming handling to core - Improved handling of Cadence module - More updates and improvements to Intel driver -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJdgFDvAAoJEHwUBw8lI4NHv7wP/Ro1MQA0WQt8GqDENFdl+JJF KTbjn0YOD4eyFKncCiUoewQghPkJUVa8598t3rNn+lhEBePRYDPh0TV44ju2pk4E FNpWmkrXih4NvfCqSPWfLB/Xap6BDvX0xO5k7BoYJ08ktwlow6hWpB7FWoV+QTmk QqTypte5GTzYf+uo3UXRGPtu2bRlORtsoL8SSGcGaRERImPC0/VMlGRdMEvf2STA eyGk/ESi9s22Hl4sEKqk2uDmzUfc7uK6Ey6Ln/hhkQD7K+esmb0fFIU0JguiZo1O GAmbFsncV0Zk7bwU8oy4ZSo5Rjk2nuXMbEKWC+HLPA73skz09QyZJbqetimluzgl N7BFBVHFA0eLzFtUNieeQjcbNmOIW/rEJLO2iVPHvnOq4OLuEpFMPRhDFkMxD+cH 7COoZNg8CXeXqceK+dgEe1A8W7ujWpXMN8fuV1ugbMDkZKy08pRL55RBGWcTroxw PakDXz5fnqthfvMwb6/jmg1WqzDe0qhIRWub+Sga1wmJMN5qm3iSAYZPqZe6SiNl is4zX6w9SO8S/qBI2Y64n1vgTsHbHvSrvPRIxDs9J6TfgeAoXtlJCsNpSa3LDqV9 KxD+IV7D6MqAILUhlPK6PcMmoPBEOrFxONoOwzokd3NRQk4ZwffasXchwjDETvdc H3yzDAfUYvXPNHsHxw65 =UILk -----END PGP SIGNATURE----- Merge tag 'soundwire-5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire Pull soundwire updates from Vinod Koul: "This includes DT support thanks to Srini and more work done by Intel (Pierre) on improving cadence and intel support. Summary: - Add DT bindings and DT support in core - Add debugfs support for soundwire properties - Improvements on streaming handling to core - Improved handling of Cadence module - More updates and improvements to Intel driver" * tag 'soundwire-5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: (30 commits) soundwire: stream: make stream name a const pointer soundwire: Add compute_params callback soundwire: core: add device tree support for slave devices dt-bindings: soundwire: add slave bindings soundwire: bus: set initial value to port_status soundwire: intel: handle disabled links soundwire: intel: add debugfs register dump soundwire: cadence_master: add debugfs register dump soundwire: add debugfs support soundwire: intel: remove unused variables soundwire: intel: move shutdown() callback and don't export symbol soundwire: cadence_master: add kernel parameter to override interrupt mask soundwire: intel_init: add kernel module parameter to filter out links soundwire: cadence_master: fix divider setting in clock register soundwire: cadence_master: make use of mclk_freq property soundwire: intel: read mclk_freq property from firmware soundwire: add new mclk_freq field for properties soundwire: stream: remove unnecessary variable initializations soundwire: stream: fix disable sequence soundwire: include mod_devicetable.h to avoid compiling warnings ...
This commit is contained in:
commit
8d7ead5c69
|
@ -0,0 +1,82 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/soundwire/soundwire-controller.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: SoundWire Controller Generic Binding
|
||||
|
||||
maintainers:
|
||||
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
- Vinod Koul <vkoul@kernel.org>
|
||||
|
||||
description: |
|
||||
SoundWire busses can be described with a node for the SoundWire controller
|
||||
device and a set of child nodes for each SoundWire slave on the bus.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^soundwire(@.*)?$"
|
||||
|
||||
"#address-cells":
|
||||
const: 2
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^.*@[0-9a-f],[0-9a-f]$":
|
||||
type: object
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
pattern: "^sdw[0-9a-f]{1}[0-9a-f]{4}[0-9a-f]{4}[0-9a-f]{2}$"
|
||||
description: Is the textual representation of SoundWire Enumeration
|
||||
address. compatible string should contain SoundWire Version ID,
|
||||
Manufacturer ID, Part ID and Class ID in order and shall be in
|
||||
lower-case hexadecimal with leading zeroes.
|
||||
Valid sizes of these fields are
|
||||
Version ID is 1 nibble, number '0x1' represents SoundWire 1.0
|
||||
and '0x2' represents SoundWire 1.1 and so on.
|
||||
MFD is 4 nibbles
|
||||
PID is 4 nibbles
|
||||
CID is 2 nibbles
|
||||
More Information on detail of encoding of these fields can be
|
||||
found in MIPI Alliance DisCo & SoundWire 1.0 Specifications.
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description:
|
||||
Link ID followed by Instance ID of SoundWire Device Address.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
examples:
|
||||
- |
|
||||
soundwire@c2d0000 {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x0c2d0000 0x2000>;
|
||||
|
||||
speaker@0,1 {
|
||||
compatible = "sdw10217201000";
|
||||
reg = <0 1>;
|
||||
powerdown-gpios = <&wcdpinctrl 2 0>;
|
||||
#thermal-sensor-cells = <0>;
|
||||
};
|
||||
|
||||
speaker@0,2 {
|
||||
compatible = "sdw10217201000";
|
||||
reg = <0 2>;
|
||||
powerdown-gpios = <&wcdpinctrl 2 0>;
|
||||
#thermal-sensor-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -7,6 +7,10 @@
|
|||
soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o
|
||||
obj-$(CONFIG_SOUNDWIRE) += soundwire-bus.o
|
||||
|
||||
ifdef CONFIG_DEBUG_FS
|
||||
soundwire-bus-objs += debugfs.o
|
||||
endif
|
||||
|
||||
#Cadence Objs
|
||||
soundwire-cadence-objs := cadence_master.o
|
||||
obj-$(CONFIG_SOUNDWIRE_CADENCE) += soundwire-cadence.o
|
||||
|
|
|
@ -49,6 +49,8 @@ int sdw_add_bus_master(struct sdw_bus *bus)
|
|||
}
|
||||
}
|
||||
|
||||
sdw_bus_debugfs_init(bus);
|
||||
|
||||
/*
|
||||
* Device numbers in SoundWire are 0 through 15. Enumeration device
|
||||
* number (0), Broadcast device number (15), Group numbers (12 and
|
||||
|
@ -77,6 +79,8 @@ int sdw_add_bus_master(struct sdw_bus *bus)
|
|||
*/
|
||||
if (IS_ENABLED(CONFIG_ACPI) && ACPI_HANDLE(bus->dev))
|
||||
ret = sdw_acpi_find_slaves(bus);
|
||||
else if (IS_ENABLED(CONFIG_OF) && bus->dev->of_node)
|
||||
ret = sdw_of_find_slaves(bus);
|
||||
else
|
||||
ret = -ENOTSUPP; /* No ACPI/DT so error out */
|
||||
|
||||
|
@ -109,6 +113,8 @@ static int sdw_delete_slave(struct device *dev, void *data)
|
|||
struct sdw_slave *slave = dev_to_sdw_dev(dev);
|
||||
struct sdw_bus *bus = slave->bus;
|
||||
|
||||
sdw_slave_debugfs_exit(slave);
|
||||
|
||||
mutex_lock(&bus->bus_lock);
|
||||
|
||||
if (slave->dev_num) /* clear dev_num if assigned */
|
||||
|
@ -130,6 +136,8 @@ static int sdw_delete_slave(struct device *dev, void *data)
|
|||
void sdw_delete_bus_master(struct sdw_bus *bus)
|
||||
{
|
||||
device_for_each_child(bus->dev, NULL, sdw_delete_slave);
|
||||
|
||||
sdw_bus_debugfs_exit(bus);
|
||||
}
|
||||
EXPORT_SYMBOL(sdw_delete_bus_master);
|
||||
|
||||
|
@ -470,7 +478,8 @@ static int sdw_assign_device_num(struct sdw_slave *slave)
|
|||
|
||||
ret = sdw_write(slave, SDW_SCP_DEVNUMBER, dev_num);
|
||||
if (ret < 0) {
|
||||
dev_err(&slave->dev, "Program device_num failed: %d\n", ret);
|
||||
dev_err(&slave->dev, "Program device_num %d failed: %d\n",
|
||||
dev_num, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -527,6 +536,7 @@ static int sdw_program_device_num(struct sdw_bus *bus)
|
|||
do {
|
||||
ret = sdw_transfer(bus, &msg);
|
||||
if (ret == -ENODATA) { /* end of device id reads */
|
||||
dev_dbg(bus->dev, "No more devices to enumerate\n");
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -803,7 +813,7 @@ static int sdw_handle_port_interrupt(struct sdw_slave *slave,
|
|||
static int sdw_handle_slave_alerts(struct sdw_slave *slave)
|
||||
{
|
||||
struct sdw_slave_intr_status slave_intr;
|
||||
u8 clear = 0, bit, port_status[15];
|
||||
u8 clear = 0, bit, port_status[15] = {0};
|
||||
int port_num, stat, ret, count = 0;
|
||||
unsigned long port;
|
||||
bool slave_notify = false;
|
||||
|
@ -969,9 +979,15 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
|
|||
int i, ret = 0;
|
||||
|
||||
if (status[0] == SDW_SLAVE_ATTACHED) {
|
||||
dev_dbg(bus->dev, "Slave attached, programming device number\n");
|
||||
ret = sdw_program_device_num(bus);
|
||||
if (ret)
|
||||
dev_err(bus->dev, "Slave attach failed: %d\n", ret);
|
||||
/*
|
||||
* programming a device number will have side effects,
|
||||
* so we deal with other devices at a later time
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Continue to check other slave statuses */
|
||||
|
|
|
@ -15,9 +15,26 @@ static inline int sdw_acpi_find_slaves(struct sdw_bus *bus)
|
|||
}
|
||||
#endif
|
||||
|
||||
int sdw_of_find_slaves(struct sdw_bus *bus);
|
||||
void sdw_extract_slave_id(struct sdw_bus *bus,
|
||||
u64 addr, struct sdw_slave_id *id);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void sdw_bus_debugfs_init(struct sdw_bus *bus);
|
||||
void sdw_bus_debugfs_exit(struct sdw_bus *bus);
|
||||
void sdw_slave_debugfs_init(struct sdw_slave *slave);
|
||||
void sdw_slave_debugfs_exit(struct sdw_slave *slave);
|
||||
void sdw_debugfs_init(void);
|
||||
void sdw_debugfs_exit(void);
|
||||
#else
|
||||
static inline void sdw_bus_debugfs_init(struct sdw_bus *bus) {}
|
||||
static inline void sdw_bus_debugfs_exit(struct sdw_bus *bus) {}
|
||||
static inline void sdw_slave_debugfs_init(struct sdw_slave *slave) {}
|
||||
static inline void sdw_slave_debugfs_exit(struct sdw_slave *slave) {}
|
||||
static inline void sdw_debugfs_init(void) {}
|
||||
static inline void sdw_debugfs_exit(void) {}
|
||||
#endif
|
||||
|
||||
enum {
|
||||
SDW_MSG_FLAG_READ = 0,
|
||||
SDW_MSG_FLAG_WRITE,
|
||||
|
@ -49,8 +66,11 @@ struct sdw_msg {
|
|||
|
||||
#define SDW_DOUBLE_RATE_FACTOR 2
|
||||
|
||||
extern int rows[SDW_FRAME_ROWS];
|
||||
extern int cols[SDW_FRAME_COLS];
|
||||
extern int sdw_rows[SDW_FRAME_ROWS];
|
||||
extern int sdw_cols[SDW_FRAME_COLS];
|
||||
|
||||
int sdw_find_row_index(int row);
|
||||
int sdw_find_col_index(int col);
|
||||
|
||||
/**
|
||||
* sdw_port_runtime: Runtime port parameters for Master or Slave
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <linux/pm_domain.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include "bus.h"
|
||||
|
||||
/**
|
||||
* sdw_get_device_id - find the matching SoundWire device id
|
||||
|
@ -177,11 +178,13 @@ EXPORT_SYMBOL_GPL(sdw_unregister_driver);
|
|||
|
||||
static int __init sdw_bus_init(void)
|
||||
{
|
||||
sdw_debugfs_init();
|
||||
return bus_register(&sdw_bus_type);
|
||||
}
|
||||
|
||||
static void __exit sdw_bus_exit(void)
|
||||
{
|
||||
sdw_debugfs_exit();
|
||||
bus_unregister(&sdw_bus_type);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -19,6 +20,10 @@
|
|||
#include "bus.h"
|
||||
#include "cadence_master.h"
|
||||
|
||||
static int interrupt_mask;
|
||||
module_param_named(cnds_mcp_int_mask, interrupt_mask, int, 0444);
|
||||
MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");
|
||||
|
||||
#define CDNS_MCP_CONFIG 0x0
|
||||
|
||||
#define CDNS_MCP_CONFIG_MCMD_RETRY GENMASK(27, 24)
|
||||
|
@ -47,6 +52,8 @@
|
|||
#define CDNS_MCP_SSPSTAT 0xC
|
||||
#define CDNS_MCP_FRAME_SHAPE 0x10
|
||||
#define CDNS_MCP_FRAME_SHAPE_INIT 0x14
|
||||
#define CDNS_MCP_FRAME_SHAPE_COL_MASK GENMASK(2, 0)
|
||||
#define CDNS_MCP_FRAME_SHAPE_ROW_OFFSET 3
|
||||
|
||||
#define CDNS_MCP_CONFIG_UPDATE 0x18
|
||||
#define CDNS_MCP_CONFIG_UPDATE_BIT BIT(0)
|
||||
|
@ -56,6 +63,7 @@
|
|||
#define CDNS_MCP_SSP_CTRL1 0x28
|
||||
#define CDNS_MCP_CLK_CTRL0 0x30
|
||||
#define CDNS_MCP_CLK_CTRL1 0x38
|
||||
#define CDNS_MCP_CLK_MCLKD_MASK GENMASK(7, 0)
|
||||
|
||||
#define CDNS_MCP_STAT 0x40
|
||||
|
||||
|
@ -75,9 +83,12 @@
|
|||
#define CDNS_MCP_INT_DPINT BIT(11)
|
||||
#define CDNS_MCP_INT_CTRL_CLASH BIT(10)
|
||||
#define CDNS_MCP_INT_DATA_CLASH BIT(9)
|
||||
#define CDNS_MCP_INT_PARITY BIT(8)
|
||||
#define CDNS_MCP_INT_CMD_ERR BIT(7)
|
||||
#define CDNS_MCP_INT_RX_NE BIT(3)
|
||||
#define CDNS_MCP_INT_RX_WL BIT(2)
|
||||
#define CDNS_MCP_INT_TXE BIT(1)
|
||||
#define CDNS_MCP_INT_TXF BIT(0)
|
||||
|
||||
#define CDNS_MCP_INTSET 0x4C
|
||||
|
||||
|
@ -169,9 +180,6 @@
|
|||
#define CDNS_PDI_CONFIG_PORT GENMASK(4, 0)
|
||||
|
||||
/* Driver defaults */
|
||||
|
||||
#define CDNS_DEFAULT_CLK_DIVIDER 0
|
||||
#define CDNS_DEFAULT_FRAME_SHAPE 0x30
|
||||
#define CDNS_DEFAULT_SSP_INTERVAL 0x18
|
||||
#define CDNS_TX_TIMEOUT 2000
|
||||
|
||||
|
@ -223,6 +231,112 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value)
|
|||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* debugfs
|
||||
*/
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
#define RD_BUF (2 * PAGE_SIZE)
|
||||
|
||||
static ssize_t cdns_sprintf(struct sdw_cdns *cdns,
|
||||
char *buf, size_t pos, unsigned int reg)
|
||||
{
|
||||
return scnprintf(buf + pos, RD_BUF - pos,
|
||||
"%4x\t%8x\n", reg, cdns_readl(cdns, reg));
|
||||
}
|
||||
|
||||
static int cdns_reg_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct sdw_cdns *cdns = s->private;
|
||||
char *buf;
|
||||
ssize_t ret;
|
||||
int num_ports;
|
||||
int i, j;
|
||||
|
||||
buf = kzalloc(RD_BUF, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = scnprintf(buf, RD_BUF, "Register Value\n");
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "\nMCP Registers\n");
|
||||
/* 8 MCP registers */
|
||||
for (i = CDNS_MCP_CONFIG; i <= CDNS_MCP_PHYCTRL; i += sizeof(u32))
|
||||
ret += cdns_sprintf(cdns, buf, ret, i);
|
||||
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret,
|
||||
"\nStatus & Intr Registers\n");
|
||||
/* 13 Status & Intr registers (offsets 0x70 and 0x74 not defined) */
|
||||
for (i = CDNS_MCP_STAT; i <= CDNS_MCP_FIFOSTAT; i += sizeof(u32))
|
||||
ret += cdns_sprintf(cdns, buf, ret, i);
|
||||
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret,
|
||||
"\nSSP & Clk ctrl Registers\n");
|
||||
ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL0);
|
||||
ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL1);
|
||||
ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL0);
|
||||
ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL1);
|
||||
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret,
|
||||
"\nDPn B0 Registers\n");
|
||||
|
||||
/*
|
||||
* in sdw_cdns_pdi_init() we filter out the Bulk PDIs,
|
||||
* so the indices need to be corrected again
|
||||
*/
|
||||
num_ports = cdns->num_ports + CDNS_PCM_PDI_OFFSET;
|
||||
|
||||
for (i = 0; i < num_ports; i++) {
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret,
|
||||
"\nDP-%d\n", i);
|
||||
for (j = CDNS_DPN_B0_CONFIG(i);
|
||||
j < CDNS_DPN_B0_ASYNC_CTRL(i); j += sizeof(u32))
|
||||
ret += cdns_sprintf(cdns, buf, ret, j);
|
||||
}
|
||||
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret,
|
||||
"\nDPn B1 Registers\n");
|
||||
for (i = 0; i < num_ports; i++) {
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret,
|
||||
"\nDP-%d\n", i);
|
||||
|
||||
for (j = CDNS_DPN_B1_CONFIG(i);
|
||||
j < CDNS_DPN_B1_ASYNC_CTRL(i); j += sizeof(u32))
|
||||
ret += cdns_sprintf(cdns, buf, ret, j);
|
||||
}
|
||||
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret,
|
||||
"\nDPn Control Registers\n");
|
||||
for (i = 0; i < num_ports; i++)
|
||||
ret += cdns_sprintf(cdns, buf, ret,
|
||||
CDNS_PORTCTRL + i * CDNS_PORT_OFFSET);
|
||||
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret,
|
||||
"\nPDIn Config Registers\n");
|
||||
|
||||
/* number of PDI and ports is interchangeable */
|
||||
for (i = 0; i < num_ports; i++)
|
||||
ret += cdns_sprintf(cdns, buf, ret, CDNS_PDI_CONFIG(i));
|
||||
|
||||
seq_printf(s, "%s", buf);
|
||||
kfree(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(cdns_reg);
|
||||
|
||||
/**
|
||||
* sdw_cdns_debugfs_init() - Cadence debugfs init
|
||||
* @cdns: Cadence instance
|
||||
* @root: debugfs root
|
||||
*/
|
||||
void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root)
|
||||
{
|
||||
debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init);
|
||||
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
/*
|
||||
* IO Calls
|
||||
*/
|
||||
|
@ -575,10 +689,14 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
|
|||
}
|
||||
}
|
||||
|
||||
if (int_status & CDNS_MCP_INT_PARITY) {
|
||||
/* Parity error detected by Master */
|
||||
dev_err_ratelimited(cdns->dev, "Parity error\n");
|
||||
}
|
||||
|
||||
if (int_status & CDNS_MCP_INT_CTRL_CLASH) {
|
||||
/* Slave is driving bit slot during control word */
|
||||
dev_err_ratelimited(cdns->dev, "Bus clash for control word\n");
|
||||
int_status |= CDNS_MCP_INT_CTRL_CLASH;
|
||||
}
|
||||
|
||||
if (int_status & CDNS_MCP_INT_DATA_CLASH) {
|
||||
|
@ -587,7 +705,6 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
|
|||
* ownership of data bits or Slave gone bonkers
|
||||
*/
|
||||
dev_err_ratelimited(cdns->dev, "Bus clash for data word\n");
|
||||
int_status |= CDNS_MCP_INT_DATA_CLASH;
|
||||
}
|
||||
|
||||
if (int_status & CDNS_MCP_INT_SLAVE_MASK) {
|
||||
|
@ -644,10 +761,26 @@ static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
|
|||
cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1,
|
||||
CDNS_MCP_SLAVE_INTMASK1_MASK);
|
||||
|
||||
mask = CDNS_MCP_INT_SLAVE_RSVD | CDNS_MCP_INT_SLAVE_ALERT |
|
||||
CDNS_MCP_INT_SLAVE_ATTACH | CDNS_MCP_INT_SLAVE_NATTACH |
|
||||
CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
|
||||
CDNS_MCP_INT_RX_WL | CDNS_MCP_INT_IRQ | CDNS_MCP_INT_DPINT;
|
||||
/* enable detection of all slave state changes */
|
||||
mask = CDNS_MCP_INT_SLAVE_MASK;
|
||||
|
||||
/* enable detection of bus issues */
|
||||
mask |= CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
|
||||
CDNS_MCP_INT_PARITY;
|
||||
|
||||
/* no detection of port interrupts for now */
|
||||
|
||||
/* enable detection of RX fifo level */
|
||||
mask |= CDNS_MCP_INT_RX_WL;
|
||||
|
||||
/*
|
||||
* CDNS_MCP_INT_IRQ needs to be set otherwise all previous
|
||||
* settings are irrelevant
|
||||
*/
|
||||
mask |= CDNS_MCP_INT_IRQ;
|
||||
|
||||
if (interrupt_mask) /* parameter override */
|
||||
mask = interrupt_mask;
|
||||
|
||||
cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
|
||||
|
||||
|
@ -788,13 +921,30 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
|
|||
}
|
||||
EXPORT_SYMBOL(sdw_cdns_pdi_init);
|
||||
|
||||
static u32 cdns_set_initial_frame_shape(int n_rows, int n_cols)
|
||||
{
|
||||
u32 val;
|
||||
int c;
|
||||
int r;
|
||||
|
||||
r = sdw_find_row_index(n_rows);
|
||||
c = sdw_find_col_index(n_cols) & CDNS_MCP_FRAME_SHAPE_COL_MASK;
|
||||
|
||||
val = (r << CDNS_MCP_FRAME_SHAPE_ROW_OFFSET) | c;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* sdw_cdns_init() - Cadence initialization
|
||||
* @cdns: Cadence instance
|
||||
*/
|
||||
int sdw_cdns_init(struct sdw_cdns *cdns)
|
||||
{
|
||||
struct sdw_bus *bus = &cdns->bus;
|
||||
struct sdw_master_prop *prop = &bus->prop;
|
||||
u32 val;
|
||||
int divider;
|
||||
int ret;
|
||||
|
||||
/* Exit clock stop */
|
||||
|
@ -806,12 +956,20 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
|
|||
}
|
||||
|
||||
/* Set clock divider */
|
||||
val = cdns_readl(cdns, CDNS_MCP_CLK_CTRL0);
|
||||
val |= CDNS_DEFAULT_CLK_DIVIDER;
|
||||
cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
|
||||
divider = (prop->mclk_freq / prop->max_clk_freq) - 1;
|
||||
|
||||
/* Set the default frame shape */
|
||||
cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT, CDNS_DEFAULT_FRAME_SHAPE);
|
||||
cdns_updatel(cdns, CDNS_MCP_CLK_CTRL0,
|
||||
CDNS_MCP_CLK_MCLKD_MASK, divider);
|
||||
cdns_updatel(cdns, CDNS_MCP_CLK_CTRL1,
|
||||
CDNS_MCP_CLK_MCLKD_MASK, divider);
|
||||
|
||||
/*
|
||||
* Frame shape changes after initialization have to be done
|
||||
* with the bank switch mechanism
|
||||
*/
|
||||
val = cdns_set_initial_frame_shape(prop->default_row,
|
||||
prop->default_col);
|
||||
cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT, val);
|
||||
|
||||
/* Set SSP interval to default value */
|
||||
cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, CDNS_DEFAULT_SSP_INTERVAL);
|
||||
|
@ -851,8 +1009,9 @@ EXPORT_SYMBOL(sdw_cdns_init);
|
|||
|
||||
int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
|
||||
{
|
||||
struct sdw_master_prop *prop = &bus->prop;
|
||||
struct sdw_cdns *cdns = bus_to_cdns(bus);
|
||||
int mcp_clkctrl_off, mcp_clkctrl;
|
||||
int mcp_clkctrl_off;
|
||||
int divider;
|
||||
|
||||
if (!params->curr_dr_freq) {
|
||||
|
@ -860,16 +1019,16 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
divider = (params->max_dr_freq / params->curr_dr_freq) - 1;
|
||||
divider = prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR /
|
||||
params->curr_dr_freq;
|
||||
divider--; /* divider is 1/(N+1) */
|
||||
|
||||
if (params->next_bank)
|
||||
mcp_clkctrl_off = CDNS_MCP_CLK_CTRL1;
|
||||
else
|
||||
mcp_clkctrl_off = CDNS_MCP_CLK_CTRL0;
|
||||
|
||||
mcp_clkctrl = cdns_readl(cdns, mcp_clkctrl_off);
|
||||
mcp_clkctrl |= divider;
|
||||
cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl);
|
||||
cdns_updatel(cdns, mcp_clkctrl_off, CDNS_MCP_CLK_MCLKD_MASK, divider);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1170,19 +1329,5 @@ int sdw_cdns_alloc_stream(struct sdw_cdns *cdns,
|
|||
}
|
||||
EXPORT_SYMBOL(sdw_cdns_alloc_stream);
|
||||
|
||||
void sdw_cdns_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sdw_cdns_dma_data *dma;
|
||||
|
||||
dma = snd_soc_dai_get_dma_data(dai, substream);
|
||||
if (!dma)
|
||||
return;
|
||||
|
||||
snd_soc_dai_set_dma_data(dai, substream, NULL);
|
||||
kfree(dma);
|
||||
}
|
||||
EXPORT_SYMBOL(sdw_cdns_shutdown);
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_DESCRIPTION("Cadence Soundwire Library");
|
||||
|
|
|
@ -163,6 +163,10 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
|
|||
struct sdw_cdns_stream_config config);
|
||||
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
|
||||
#endif
|
||||
|
||||
int sdw_cdns_get_stream(struct sdw_cdns *cdns,
|
||||
struct sdw_cdns_streams *stream,
|
||||
u32 ch, u32 dir);
|
||||
|
@ -172,8 +176,6 @@ int sdw_cdns_alloc_stream(struct sdw_cdns *cdns,
|
|||
void sdw_cdns_config_stream(struct sdw_cdns *cdns, struct sdw_cdns_port *port,
|
||||
u32 ch, u32 dir, struct sdw_cdns_pdi *pdi);
|
||||
|
||||
void sdw_cdns_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai);
|
||||
int sdw_cdns_pcm_set_stream(struct snd_soc_dai *dai,
|
||||
void *stream, int direction);
|
||||
int sdw_cdns_pdm_set_stream(struct snd_soc_dai *dai,
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright(c) 2017-2019 Intel Corporation.
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_registers.h>
|
||||
#include "bus.h"
|
||||
|
||||
static struct dentry *sdw_debugfs_root;
|
||||
|
||||
void sdw_bus_debugfs_init(struct sdw_bus *bus)
|
||||
{
|
||||
char name[16];
|
||||
|
||||
if (!sdw_debugfs_root)
|
||||
return;
|
||||
|
||||
/* create the debugfs master-N */
|
||||
snprintf(name, sizeof(name), "master-%d", bus->link_id);
|
||||
bus->debugfs = debugfs_create_dir(name, sdw_debugfs_root);
|
||||
}
|
||||
|
||||
void sdw_bus_debugfs_exit(struct sdw_bus *bus)
|
||||
{
|
||||
debugfs_remove_recursive(bus->debugfs);
|
||||
}
|
||||
|
||||
#define RD_BUF (3 * PAGE_SIZE)
|
||||
|
||||
static ssize_t sdw_sprintf(struct sdw_slave *slave,
|
||||
char *buf, size_t pos, unsigned int reg)
|
||||
{
|
||||
int value;
|
||||
|
||||
value = sdw_read(slave, reg);
|
||||
|
||||
if (value < 0)
|
||||
return scnprintf(buf + pos, RD_BUF - pos, "%3x\tXX\n", reg);
|
||||
else
|
||||
return scnprintf(buf + pos, RD_BUF - pos,
|
||||
"%3x\t%2x\n", reg, value);
|
||||
}
|
||||
|
||||
static int sdw_slave_reg_show(struct seq_file *s_file, void *data)
|
||||
{
|
||||
struct sdw_slave *slave = s_file->private;
|
||||
char *buf;
|
||||
ssize_t ret;
|
||||
int i, j;
|
||||
|
||||
buf = kzalloc(RD_BUF, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = scnprintf(buf, RD_BUF, "Register Value\n");
|
||||
|
||||
/* DP0 non-banked registers */
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP0\n");
|
||||
for (i = SDW_DP0_INT; i <= SDW_DP0_PREPARECTRL; i++)
|
||||
ret += sdw_sprintf(slave, buf, ret, i);
|
||||
|
||||
/* DP0 Bank 0 registers */
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
|
||||
ret += sdw_sprintf(slave, buf, ret, SDW_DP0_CHANNELEN);
|
||||
for (i = SDW_DP0_SAMPLECTRL1; i <= SDW_DP0_LANECTRL; i++)
|
||||
ret += sdw_sprintf(slave, buf, ret, i);
|
||||
|
||||
/* DP0 Bank 1 registers */
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
|
||||
ret += sdw_sprintf(slave, buf, ret,
|
||||
SDW_DP0_CHANNELEN + SDW_BANK1_OFFSET);
|
||||
for (i = SDW_DP0_SAMPLECTRL1 + SDW_BANK1_OFFSET;
|
||||
i <= SDW_DP0_LANECTRL + SDW_BANK1_OFFSET; i++)
|
||||
ret += sdw_sprintf(slave, buf, ret, i);
|
||||
|
||||
/* SCP registers */
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "\nSCP\n");
|
||||
for (i = SDW_SCP_INT1; i <= SDW_SCP_BANKDELAY; i++)
|
||||
ret += sdw_sprintf(slave, buf, ret, i);
|
||||
for (i = SDW_SCP_DEVID_0; i <= SDW_SCP_DEVID_5; i++)
|
||||
ret += sdw_sprintf(slave, buf, ret, i);
|
||||
|
||||
/*
|
||||
* SCP Bank 0/1 registers are read-only and cannot be
|
||||
* retrieved from the Slave. The Master typically keeps track
|
||||
* of the current frame size so the information can be found
|
||||
* in other places
|
||||
*/
|
||||
|
||||
/* DP1..14 registers */
|
||||
for (i = 1; SDW_VALID_PORT_RANGE(i); i++) {
|
||||
|
||||
/* DPi registers */
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP%d\n", i);
|
||||
for (j = SDW_DPN_INT(i); j <= SDW_DPN_PREPARECTRL(i); j++)
|
||||
ret += sdw_sprintf(slave, buf, ret, j);
|
||||
|
||||
/* DPi Bank0 registers */
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
|
||||
for (j = SDW_DPN_CHANNELEN_B0(i);
|
||||
j <= SDW_DPN_LANECTRL_B0(i); j++)
|
||||
ret += sdw_sprintf(slave, buf, ret, j);
|
||||
|
||||
/* DPi Bank1 registers */
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
|
||||
for (j = SDW_DPN_CHANNELEN_B1(i);
|
||||
j <= SDW_DPN_LANECTRL_B1(i); j++)
|
||||
ret += sdw_sprintf(slave, buf, ret, j);
|
||||
}
|
||||
|
||||
seq_printf(s_file, "%s", buf);
|
||||
kfree(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(sdw_slave_reg);
|
||||
|
||||
void sdw_slave_debugfs_init(struct sdw_slave *slave)
|
||||
{
|
||||
struct dentry *master;
|
||||
struct dentry *d;
|
||||
char name[32];
|
||||
|
||||
master = slave->bus->debugfs;
|
||||
|
||||
/* create the debugfs slave-name */
|
||||
snprintf(name, sizeof(name), "%s", dev_name(&slave->dev));
|
||||
d = debugfs_create_dir(name, master);
|
||||
|
||||
debugfs_create_file("registers", 0400, d, slave, &sdw_slave_reg_fops);
|
||||
|
||||
slave->debugfs = d;
|
||||
}
|
||||
|
||||
void sdw_slave_debugfs_exit(struct sdw_slave *slave)
|
||||
{
|
||||
debugfs_remove_recursive(slave->debugfs);
|
||||
}
|
||||
|
||||
void sdw_debugfs_init(void)
|
||||
{
|
||||
sdw_debugfs_root = debugfs_create_dir("soundwire", NULL);
|
||||
}
|
||||
|
||||
void sdw_debugfs_exit(void)
|
||||
{
|
||||
debugfs_remove_recursive(sdw_debugfs_root);
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
@ -16,6 +17,7 @@
|
|||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_intel.h>
|
||||
#include "cadence_master.h"
|
||||
#include "bus.h"
|
||||
#include "intel.h"
|
||||
|
||||
/* Intel SHIM Registers Definition */
|
||||
|
@ -83,11 +85,14 @@
|
|||
|
||||
/* Intel ALH Register definitions */
|
||||
#define SDW_ALH_STRMZCFG(x) (0x000 + (0x4 * (x)))
|
||||
#define SDW_ALH_NUM_STREAMS 64
|
||||
|
||||
#define SDW_ALH_STRMZCFG_DMAT_VAL 0x3
|
||||
#define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0)
|
||||
#define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16)
|
||||
|
||||
#define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1)
|
||||
|
||||
enum intel_pdi_type {
|
||||
INTEL_PDI_IN = 0,
|
||||
INTEL_PDI_OUT = 1,
|
||||
|
@ -98,6 +103,9 @@ struct sdw_intel {
|
|||
struct sdw_cdns cdns;
|
||||
int instance;
|
||||
struct sdw_intel_link_res *res;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns)
|
||||
|
@ -161,6 +169,118 @@ static int intel_set_bit(void __iomem *base, int offset, u32 value, u32 mask)
|
|||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* debugfs
|
||||
*/
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
#define RD_BUF (2 * PAGE_SIZE)
|
||||
|
||||
static ssize_t intel_sprintf(void __iomem *mem, bool l,
|
||||
char *buf, size_t pos, unsigned int reg)
|
||||
{
|
||||
int value;
|
||||
|
||||
if (l)
|
||||
value = intel_readl(mem, reg);
|
||||
else
|
||||
value = intel_readw(mem, reg);
|
||||
|
||||
return scnprintf(buf + pos, RD_BUF - pos, "%4x\t%4x\n", reg, value);
|
||||
}
|
||||
|
||||
static int intel_reg_show(struct seq_file *s_file, void *data)
|
||||
{
|
||||
struct sdw_intel *sdw = s_file->private;
|
||||
void __iomem *s = sdw->res->shim;
|
||||
void __iomem *a = sdw->res->alh;
|
||||
char *buf;
|
||||
ssize_t ret;
|
||||
int i, j;
|
||||
unsigned int links, reg;
|
||||
|
||||
buf = kzalloc(RD_BUF, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
links = intel_readl(s, SDW_SHIM_LCAP) & GENMASK(2, 0);
|
||||
|
||||
ret = scnprintf(buf, RD_BUF, "Register Value\n");
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n");
|
||||
|
||||
for (i = 0; i < links; i++) {
|
||||
reg = SDW_SHIM_LCAP + i * 4;
|
||||
ret += intel_sprintf(s, true, buf, ret, reg);
|
||||
}
|
||||
|
||||
for (i = 0; i < links; i++) {
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "\nLink%d\n", i);
|
||||
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLSCAP(i));
|
||||
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS0CM(i));
|
||||
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS1CM(i));
|
||||
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS2CM(i));
|
||||
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS3CM(i));
|
||||
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PCMSCAP(i));
|
||||
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "\n PCMSyCH registers\n");
|
||||
|
||||
/*
|
||||
* the value 10 is the number of PDIs. We will need a
|
||||
* cleanup to remove hard-coded Intel configurations
|
||||
* from cadence_master.c
|
||||
*/
|
||||
for (j = 0; j < 10; j++) {
|
||||
ret += intel_sprintf(s, false, buf, ret,
|
||||
SDW_SHIM_PCMSYCHM(i, j));
|
||||
ret += intel_sprintf(s, false, buf, ret,
|
||||
SDW_SHIM_PCMSYCHC(i, j));
|
||||
}
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "\n PDMSCAP, IOCTL, CTMCTL\n");
|
||||
|
||||
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PDMSCAP(i));
|
||||
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i));
|
||||
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i));
|
||||
}
|
||||
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "\nWake registers\n");
|
||||
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKEEN);
|
||||
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKESTS);
|
||||
|
||||
ret += scnprintf(buf + ret, RD_BUF - ret, "\nALH STRMzCFG\n");
|
||||
for (i = 0; i < SDW_ALH_NUM_STREAMS; i++)
|
||||
ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i));
|
||||
|
||||
seq_printf(s_file, "%s", buf);
|
||||
kfree(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(intel_reg);
|
||||
|
||||
static void intel_debugfs_init(struct sdw_intel *sdw)
|
||||
{
|
||||
struct dentry *root = sdw->cdns.bus.debugfs;
|
||||
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
sdw->debugfs = debugfs_create_dir("intel-sdw", root);
|
||||
|
||||
debugfs_create_file("intel-registers", 0400, sdw->debugfs, sdw,
|
||||
&intel_reg_fops);
|
||||
|
||||
sdw_cdns_debugfs_init(&sdw->cdns, sdw->debugfs);
|
||||
}
|
||||
|
||||
static void intel_debugfs_exit(struct sdw_intel *sdw)
|
||||
{
|
||||
debugfs_remove_recursive(sdw->debugfs);
|
||||
}
|
||||
#else
|
||||
static void intel_debugfs_init(struct sdw_intel *sdw) {}
|
||||
static void intel_debugfs_exit(struct sdw_intel *sdw) {}
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
/*
|
||||
* shim ops
|
||||
*/
|
||||
|
@ -289,6 +409,16 @@ intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm)
|
|||
|
||||
if (pcm) {
|
||||
count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num));
|
||||
|
||||
/*
|
||||
* WORKAROUND: on all existing Intel controllers, pdi
|
||||
* number 2 reports channel count as 1 even though it
|
||||
* supports 8 channels. Performing hardcoding for pdi
|
||||
* number 2.
|
||||
*/
|
||||
if (pdi_num == 2)
|
||||
count = 7;
|
||||
|
||||
} else {
|
||||
count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
|
||||
count = ((count & SDW_SHIM_PDMSCAP_CPSS) >>
|
||||
|
@ -397,8 +527,10 @@ static int intel_config_stream(struct sdw_intel *sdw,
|
|||
struct snd_soc_dai *dai,
|
||||
struct snd_pcm_hw_params *hw_params, int link_id)
|
||||
{
|
||||
if (sdw->res->ops && sdw->res->ops->config_stream)
|
||||
return sdw->res->ops->config_stream(sdw->res->arg,
|
||||
struct sdw_intel_link_res *res = sdw->res;
|
||||
|
||||
if (res->ops && res->ops->config_stream && res->arg)
|
||||
return res->ops->config_stream(res->arg,
|
||||
substream, dai, hw_params, link_id);
|
||||
|
||||
return -EIO;
|
||||
|
@ -649,6 +781,19 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void intel_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sdw_cdns_dma_data *dma;
|
||||
|
||||
dma = snd_soc_dai_get_dma_data(dai, substream);
|
||||
if (!dma)
|
||||
return;
|
||||
|
||||
snd_soc_dai_set_dma_data(dai, substream, NULL);
|
||||
kfree(dma);
|
||||
}
|
||||
|
||||
static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
|
||||
void *stream, int direction)
|
||||
{
|
||||
|
@ -664,14 +809,14 @@ static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai,
|
|||
static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
|
||||
.hw_params = intel_hw_params,
|
||||
.hw_free = intel_hw_free,
|
||||
.shutdown = sdw_cdns_shutdown,
|
||||
.shutdown = intel_shutdown,
|
||||
.set_sdw_stream = intel_pcm_set_sdw_stream,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops intel_pdm_dai_ops = {
|
||||
.hw_params = intel_hw_params,
|
||||
.hw_free = intel_hw_free,
|
||||
.shutdown = sdw_cdns_shutdown,
|
||||
.shutdown = intel_shutdown,
|
||||
.set_sdw_stream = intel_pdm_set_sdw_stream,
|
||||
};
|
||||
|
||||
|
@ -796,21 +941,44 @@ static int intel_register_dai(struct sdw_intel *sdw)
|
|||
dais, num_dai);
|
||||
}
|
||||
|
||||
static int sdw_master_read_intel_prop(struct sdw_bus *bus)
|
||||
{
|
||||
struct sdw_master_prop *prop = &bus->prop;
|
||||
struct fwnode_handle *link;
|
||||
char name[32];
|
||||
u32 quirk_mask;
|
||||
|
||||
/* Find master handle */
|
||||
snprintf(name, sizeof(name),
|
||||
"mipi-sdw-link-%d-subproperties", bus->link_id);
|
||||
|
||||
link = device_get_named_child_node(bus->dev, name);
|
||||
if (!link) {
|
||||
dev_err(bus->dev, "Master node %s not found\n", name);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
fwnode_property_read_u32(link,
|
||||
"intel-sdw-ip-clock",
|
||||
&prop->mclk_freq);
|
||||
|
||||
fwnode_property_read_u32(link,
|
||||
"intel-quirk-mask",
|
||||
&quirk_mask);
|
||||
|
||||
if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
|
||||
prop->hw_disabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_prop_read(struct sdw_bus *bus)
|
||||
{
|
||||
/* Initialize with default handler to read all DisCo properties */
|
||||
sdw_master_read_prop(bus);
|
||||
|
||||
/* BIOS is not giving some values correctly. So, lets override them */
|
||||
bus->prop.num_clk_freq = 1;
|
||||
bus->prop.clk_freq = devm_kcalloc(bus->dev, bus->prop.num_clk_freq,
|
||||
sizeof(*bus->prop.clk_freq),
|
||||
GFP_KERNEL);
|
||||
if (!bus->prop.clk_freq)
|
||||
return -ENOMEM;
|
||||
|
||||
bus->prop.clk_freq[0] = bus->prop.max_clk_freq;
|
||||
bus->prop.err_threshold = 5;
|
||||
/* read Intel-specific properties */
|
||||
sdw_master_read_intel_prop(bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -861,6 +1029,12 @@ static int intel_probe(struct platform_device *pdev)
|
|||
goto err_master_reg;
|
||||
}
|
||||
|
||||
if (sdw->cdns.bus.prop.hw_disabled) {
|
||||
dev_info(&pdev->dev, "SoundWire master %d is disabled, ignoring\n",
|
||||
sdw->cdns.bus.link_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize shim and controller */
|
||||
intel_link_power_up(sdw);
|
||||
intel_shim_init(sdw);
|
||||
|
@ -896,6 +1070,8 @@ static int intel_probe(struct platform_device *pdev)
|
|||
goto err_dai;
|
||||
}
|
||||
|
||||
intel_debugfs_init(sdw);
|
||||
|
||||
return 0;
|
||||
|
||||
err_dai:
|
||||
|
@ -912,8 +1088,11 @@ static int intel_remove(struct platform_device *pdev)
|
|||
|
||||
sdw = platform_get_drvdata(pdev);
|
||||
|
||||
if (!sdw->cdns.bus.prop.hw_disabled) {
|
||||
intel_debugfs_exit(sdw);
|
||||
free_irq(sdw->res->irq, sdw);
|
||||
snd_soc_unregister_component(sdw->cdns.dev);
|
||||
}
|
||||
sdw_delete_bus_master(&sdw->cdns.bus);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
#define SDW_LINK_BASE 0x30000
|
||||
#define SDW_LINK_SIZE 0x10000
|
||||
|
||||
static int link_mask;
|
||||
module_param_named(sdw_link_mask, link_mask, int, 0444);
|
||||
MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
|
||||
|
||||
struct sdw_link_data {
|
||||
struct sdw_intel_link_res res;
|
||||
struct platform_device *pdev;
|
||||
|
@ -111,6 +115,13 @@ static struct sdw_intel_ctx
|
|||
|
||||
/* Create SDW Master devices */
|
||||
for (i = 0; i < count; i++) {
|
||||
if (link_mask && !(link_mask & BIT(i))) {
|
||||
dev_dbg(&adev->dev,
|
||||
"Link %d masked, will not be enabled\n", i);
|
||||
link++;
|
||||
continue;
|
||||
}
|
||||
|
||||
link->res.irq = res->irq;
|
||||
link->res.registers = res->mmio_base + SDW_LINK_BASE
|
||||
+ (SDW_LINK_SIZE * i);
|
||||
|
|
|
@ -60,8 +60,7 @@ int sdw_master_read_prop(struct sdw_bus *bus)
|
|||
"mipi-sdw-max-clock-frequency",
|
||||
&prop->max_clk_freq);
|
||||
|
||||
nval = fwnode_property_read_u32_array(link,
|
||||
"mipi-sdw-clock-frequencies-supported", NULL, 0);
|
||||
nval = fwnode_property_count_u32(link, "mipi-sdw-clock-frequencies-supported");
|
||||
if (nval > 0) {
|
||||
prop->num_clk_freq = nval;
|
||||
prop->clk_freq = devm_kcalloc(bus->dev, prop->num_clk_freq,
|
||||
|
@ -87,8 +86,7 @@ int sdw_master_read_prop(struct sdw_bus *bus)
|
|||
}
|
||||
}
|
||||
|
||||
nval = fwnode_property_read_u32_array(link,
|
||||
"mipi-sdw-supported-clock-gears", NULL, 0);
|
||||
nval = fwnode_property_count_u32(link, "mipi-sdw-supported-clock-gears");
|
||||
if (nval > 0) {
|
||||
prop->num_clk_gears = nval;
|
||||
prop->clk_gears = devm_kcalloc(bus->dev, prop->num_clk_gears,
|
||||
|
@ -134,8 +132,7 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave,
|
|||
fwnode_property_read_u32(port, "mipi-sdw-port-min-wordlength",
|
||||
&dp0->min_word);
|
||||
|
||||
nval = fwnode_property_read_u32_array(port,
|
||||
"mipi-sdw-port-wordlength-configs", NULL, 0);
|
||||
nval = fwnode_property_count_u32(port, "mipi-sdw-port-wordlength-configs");
|
||||
if (nval > 0) {
|
||||
|
||||
dp0->num_words = nval;
|
||||
|
@ -193,8 +190,7 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
|
|||
fwnode_property_read_u32(node, "mipi-sdw-port-min-wordlength",
|
||||
&dpn[i].min_word);
|
||||
|
||||
nval = fwnode_property_read_u32_array(node,
|
||||
"mipi-sdw-port-wordlength-configs", NULL, 0);
|
||||
nval = fwnode_property_count_u32(node, "mipi-sdw-port-wordlength-configs");
|
||||
if (nval > 0) {
|
||||
dpn[i].num_words = nval;
|
||||
dpn[i].words = devm_kcalloc(&slave->dev,
|
||||
|
@ -233,8 +229,7 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
|
|||
fwnode_property_read_u32(node, "mipi-sdw-max-channel-number",
|
||||
&dpn[i].max_ch);
|
||||
|
||||
nval = fwnode_property_read_u32_array(node,
|
||||
"mipi-sdw-channel-number-list", NULL, 0);
|
||||
nval = fwnode_property_count_u32(node, "mipi-sdw-channel-number-list");
|
||||
if (nval > 0) {
|
||||
dpn[i].num_ch = nval;
|
||||
dpn[i].ch = devm_kcalloc(&slave->dev, dpn[i].num_ch,
|
||||
|
@ -248,8 +243,7 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
|
|||
dpn[i].ch, dpn[i].num_ch);
|
||||
}
|
||||
|
||||
nval = fwnode_property_read_u32_array(node,
|
||||
"mipi-sdw-channel-combination-list", NULL, 0);
|
||||
nval = fwnode_property_count_u32(node, "mipi-sdw-channel-combination-list");
|
||||
if (nval > 0) {
|
||||
dpn[i].num_ch_combinations = nval;
|
||||
dpn[i].ch_combinations = devm_kcalloc(&slave->dev,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Copyright(c) 2015-17 Intel Corporation.
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include "bus.h"
|
||||
|
@ -35,6 +36,7 @@ static int sdw_slave_add(struct sdw_bus *bus,
|
|||
|
||||
slave->dev.release = sdw_slave_release;
|
||||
slave->dev.bus = &sdw_bus_type;
|
||||
slave->dev.of_node = of_node_get(to_of_node(fwnode));
|
||||
slave->bus = bus;
|
||||
slave->status = SDW_SLAVE_UNATTACHED;
|
||||
slave->dev_num = 0;
|
||||
|
@ -56,6 +58,7 @@ static int sdw_slave_add(struct sdw_bus *bus,
|
|||
mutex_unlock(&bus->bus_lock);
|
||||
put_device(&slave->dev);
|
||||
}
|
||||
sdw_slave_debugfs_init(slave);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -112,3 +115,53 @@ int sdw_acpi_find_slaves(struct sdw_bus *bus)
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* sdw_of_find_slaves() - Find Slave devices in master device tree node
|
||||
* @bus: SDW bus instance
|
||||
*
|
||||
* Scans Master DT node for SDW child Slave devices and registers it.
|
||||
*/
|
||||
int sdw_of_find_slaves(struct sdw_bus *bus)
|
||||
{
|
||||
struct device *dev = bus->dev;
|
||||
struct device_node *node;
|
||||
|
||||
for_each_child_of_node(bus->dev->of_node, node) {
|
||||
int link_id, sdw_version, ret, len;
|
||||
const char *compat = NULL;
|
||||
struct sdw_slave_id id;
|
||||
const __be32 *addr;
|
||||
|
||||
compat = of_get_property(node, "compatible", NULL);
|
||||
if (!compat)
|
||||
continue;
|
||||
|
||||
ret = sscanf(compat, "sdw%01x%04hx%04hx%02hhx", &sdw_version,
|
||||
&id.mfg_id, &id.part_id, &id.class_id);
|
||||
|
||||
if (ret != 4) {
|
||||
dev_err(dev, "Invalid compatible string found %s\n",
|
||||
compat);
|
||||
continue;
|
||||
}
|
||||
|
||||
addr = of_get_property(node, "reg", &len);
|
||||
if (!addr || (len < 2 * sizeof(u32))) {
|
||||
dev_err(dev, "Invalid Link and Instance ID\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
link_id = be32_to_cpup(addr++);
|
||||
id.unique_id = be32_to_cpup(addr);
|
||||
id.sdw_version = sdw_version;
|
||||
|
||||
/* Check for link_id match */
|
||||
if (link_id != bus->link_id)
|
||||
continue;
|
||||
|
||||
sdw_slave_add(bus, &id, of_fwnode_handle(node));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -21,37 +21,39 @@
|
|||
* The rows are arranged as per the array index value programmed
|
||||
* in register. The index 15 has dummy value 0 in order to fill hole.
|
||||
*/
|
||||
int rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,
|
||||
int sdw_rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,
|
||||
96, 100, 120, 128, 150, 160, 250, 0,
|
||||
192, 200, 240, 256, 72, 144, 90, 180};
|
||||
|
||||
int cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};
|
||||
int sdw_cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};
|
||||
|
||||
static int sdw_find_col_index(int col)
|
||||
int sdw_find_col_index(int col)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SDW_FRAME_COLS; i++) {
|
||||
if (cols[i] == col)
|
||||
if (sdw_cols[i] == col)
|
||||
return i;
|
||||
}
|
||||
|
||||
pr_warn("Requested column not found, selecting lowest column no: 2\n");
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sdw_find_col_index);
|
||||
|
||||
static int sdw_find_row_index(int row)
|
||||
int sdw_find_row_index(int row)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SDW_FRAME_ROWS; i++) {
|
||||
if (rows[i] == row)
|
||||
if (sdw_rows[i] == row)
|
||||
return i;
|
||||
}
|
||||
|
||||
pr_warn("Requested row not found, selecting lowest row no: 48\n");
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sdw_find_row_index);
|
||||
|
||||
static int _sdw_program_slave_port_params(struct sdw_bus *bus,
|
||||
struct sdw_slave *slave,
|
||||
|
@ -367,7 +369,7 @@ static int sdw_enable_disable_master_ports(struct sdw_master_runtime *m_rt,
|
|||
static int sdw_enable_disable_ports(struct sdw_master_runtime *m_rt, bool en)
|
||||
{
|
||||
struct sdw_port_runtime *s_port, *m_port;
|
||||
struct sdw_slave_runtime *s_rt = NULL;
|
||||
struct sdw_slave_runtime *s_rt;
|
||||
int ret = 0;
|
||||
|
||||
/* Enable/Disable Slave port(s) */
|
||||
|
@ -415,7 +417,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
|
|||
struct sdw_port_runtime *p_rt,
|
||||
bool prep)
|
||||
{
|
||||
struct completion *port_ready = NULL;
|
||||
struct completion *port_ready;
|
||||
struct sdw_dpn_prop *dpn_prop;
|
||||
struct sdw_prepare_ch prep_ch;
|
||||
unsigned int time_left;
|
||||
|
@ -535,7 +537,7 @@ static int sdw_prep_deprep_master_ports(struct sdw_master_runtime *m_rt,
|
|||
*/
|
||||
static int sdw_prep_deprep_ports(struct sdw_master_runtime *m_rt, bool prep)
|
||||
{
|
||||
struct sdw_slave_runtime *s_rt = NULL;
|
||||
struct sdw_slave_runtime *s_rt;
|
||||
struct sdw_port_runtime *p_rt;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -603,7 +605,7 @@ static int sdw_notify_config(struct sdw_master_runtime *m_rt)
|
|||
*/
|
||||
static int sdw_program_params(struct sdw_bus *bus)
|
||||
{
|
||||
struct sdw_master_runtime *m_rt = NULL;
|
||||
struct sdw_master_runtime *m_rt;
|
||||
int ret = 0;
|
||||
|
||||
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
|
||||
|
@ -640,8 +642,8 @@ static int sdw_bank_switch(struct sdw_bus *bus, int m_rt_count)
|
|||
int col_index, row_index;
|
||||
bool multi_link;
|
||||
struct sdw_msg *wr_msg;
|
||||
u8 *wbuf = NULL;
|
||||
int ret = 0;
|
||||
u8 *wbuf;
|
||||
int ret;
|
||||
u16 addr;
|
||||
|
||||
wr_msg = kzalloc(sizeof(*wr_msg), GFP_KERNEL);
|
||||
|
@ -739,9 +741,9 @@ static int sdw_ml_sync_bank_switch(struct sdw_bus *bus)
|
|||
|
||||
static int do_bank_switch(struct sdw_stream_runtime *stream)
|
||||
{
|
||||
struct sdw_master_runtime *m_rt = NULL;
|
||||
struct sdw_master_runtime *m_rt;
|
||||
const struct sdw_master_ops *ops;
|
||||
struct sdw_bus *bus = NULL;
|
||||
struct sdw_bus *bus;
|
||||
bool multi_link = false;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -863,7 +865,7 @@ EXPORT_SYMBOL(sdw_release_stream);
|
|||
* sdw_alloc_stream should be called only once per stream. Typically
|
||||
* invoked from ALSA/ASoC machine/platform driver.
|
||||
*/
|
||||
struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name)
|
||||
struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name)
|
||||
{
|
||||
struct sdw_stream_runtime *stream;
|
||||
|
||||
|
@ -884,7 +886,7 @@ static struct sdw_master_runtime
|
|||
*sdw_find_master_rt(struct sdw_bus *bus,
|
||||
struct sdw_stream_runtime *stream)
|
||||
{
|
||||
struct sdw_master_runtime *m_rt = NULL;
|
||||
struct sdw_master_runtime *m_rt;
|
||||
|
||||
/* Retrieve Bus handle if already available */
|
||||
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
|
||||
|
@ -953,7 +955,7 @@ static struct sdw_slave_runtime
|
|||
struct sdw_stream_config *stream_config,
|
||||
struct sdw_stream_runtime *stream)
|
||||
{
|
||||
struct sdw_slave_runtime *s_rt = NULL;
|
||||
struct sdw_slave_runtime *s_rt;
|
||||
|
||||
s_rt = kzalloc(sizeof(*s_rt), GFP_KERNEL);
|
||||
if (!s_rt)
|
||||
|
@ -1259,7 +1261,7 @@ int sdw_stream_add_master(struct sdw_bus *bus,
|
|||
unsigned int num_ports,
|
||||
struct sdw_stream_runtime *stream)
|
||||
{
|
||||
struct sdw_master_runtime *m_rt = NULL;
|
||||
struct sdw_master_runtime *m_rt;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&bus->bus_lock);
|
||||
|
@ -1426,7 +1428,7 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
|
|||
*/
|
||||
static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream)
|
||||
{
|
||||
struct sdw_master_runtime *m_rt = NULL;
|
||||
struct sdw_master_runtime *m_rt;
|
||||
struct sdw_bus *bus = NULL;
|
||||
|
||||
/* Iterate for all Master(s) in Master list */
|
||||
|
@ -1460,9 +1462,9 @@ static void sdw_release_bus_lock(struct sdw_stream_runtime *stream)
|
|||
|
||||
static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
|
||||
{
|
||||
struct sdw_master_runtime *m_rt = NULL;
|
||||
struct sdw_master_runtime *m_rt;
|
||||
struct sdw_bus *bus = NULL;
|
||||
struct sdw_master_prop *prop = NULL;
|
||||
struct sdw_master_prop *prop;
|
||||
struct sdw_bus_params params;
|
||||
int ret;
|
||||
|
||||
|
@ -1483,6 +1485,16 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
|
|||
bus->params.bandwidth += m_rt->stream->params.rate *
|
||||
m_rt->ch_count * m_rt->stream->params.bps;
|
||||
|
||||
/* Compute params */
|
||||
if (bus->compute_params) {
|
||||
ret = bus->compute_params(bus);
|
||||
if (ret < 0) {
|
||||
dev_err(bus->dev, "Compute params failed: %d",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Program params */
|
||||
ret = sdw_program_params(bus);
|
||||
if (ret < 0) {
|
||||
|
@ -1491,6 +1503,11 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
|
|||
}
|
||||
}
|
||||
|
||||
if (!bus) {
|
||||
pr_err("Configuration error in %s\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = do_bank_switch(stream);
|
||||
if (ret < 0) {
|
||||
dev_err(bus->dev, "Bank switch failed: %d\n", ret);
|
||||
|
@ -1547,7 +1564,7 @@ EXPORT_SYMBOL(sdw_prepare_stream);
|
|||
|
||||
static int _sdw_enable_stream(struct sdw_stream_runtime *stream)
|
||||
{
|
||||
struct sdw_master_runtime *m_rt = NULL;
|
||||
struct sdw_master_runtime *m_rt;
|
||||
struct sdw_bus *bus = NULL;
|
||||
int ret;
|
||||
|
||||
|
@ -1571,6 +1588,11 @@ static int _sdw_enable_stream(struct sdw_stream_runtime *stream)
|
|||
}
|
||||
}
|
||||
|
||||
if (!bus) {
|
||||
pr_err("Configuration error in %s\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = do_bank_switch(stream);
|
||||
if (ret < 0) {
|
||||
dev_err(bus->dev, "Bank switch failed: %d\n", ret);
|
||||
|
@ -1590,7 +1612,7 @@ static int _sdw_enable_stream(struct sdw_stream_runtime *stream)
|
|||
*/
|
||||
int sdw_enable_stream(struct sdw_stream_runtime *stream)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
if (!stream) {
|
||||
pr_err("SoundWire: Handle not found for stream\n");
|
||||
|
@ -1610,12 +1632,12 @@ EXPORT_SYMBOL(sdw_enable_stream);
|
|||
|
||||
static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
|
||||
{
|
||||
struct sdw_master_runtime *m_rt = NULL;
|
||||
struct sdw_bus *bus = NULL;
|
||||
struct sdw_master_runtime *m_rt;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
|
||||
bus = m_rt->bus;
|
||||
struct sdw_bus *bus = m_rt->bus;
|
||||
|
||||
/* Disable port(s) */
|
||||
ret = sdw_enable_disable_ports(m_rt, false);
|
||||
if (ret < 0) {
|
||||
|
@ -1626,7 +1648,8 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
|
|||
stream->state = SDW_STREAM_DISABLED;
|
||||
|
||||
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
|
||||
bus = m_rt->bus;
|
||||
struct sdw_bus *bus = m_rt->bus;
|
||||
|
||||
/* Program params */
|
||||
ret = sdw_program_params(bus);
|
||||
if (ret < 0) {
|
||||
|
@ -1635,7 +1658,25 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
|
|||
}
|
||||
}
|
||||
|
||||
return do_bank_switch(stream);
|
||||
ret = do_bank_switch(stream);
|
||||
if (ret < 0) {
|
||||
pr_err("Bank switch failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* make sure alternate bank (previous current) is also disabled */
|
||||
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
|
||||
struct sdw_bus *bus = m_rt->bus;
|
||||
|
||||
/* Disable port(s) */
|
||||
ret = sdw_enable_disable_ports(m_rt, false);
|
||||
if (ret < 0) {
|
||||
dev_err(bus->dev, "Disable port(s) failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1647,7 +1688,7 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
|
|||
*/
|
||||
int sdw_disable_stream(struct sdw_stream_runtime *stream)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
if (!stream) {
|
||||
pr_err("SoundWire: Handle not found for stream\n");
|
||||
|
@ -1667,8 +1708,8 @@ EXPORT_SYMBOL(sdw_disable_stream);
|
|||
|
||||
static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
|
||||
{
|
||||
struct sdw_master_runtime *m_rt = NULL;
|
||||
struct sdw_bus *bus = NULL;
|
||||
struct sdw_master_runtime *m_rt;
|
||||
struct sdw_bus *bus;
|
||||
int ret = 0;
|
||||
|
||||
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
|
||||
|
@ -1706,7 +1747,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
|
|||
*/
|
||||
int sdw_deprepare_stream(struct sdw_stream_runtime *stream)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
if (!stream) {
|
||||
pr_err("SoundWire: Handle not found for stream\n");
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#ifndef __SOUNDWIRE_H
|
||||
#define __SOUNDWIRE_H
|
||||
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
struct sdw_bus;
|
||||
struct sdw_slave;
|
||||
|
||||
|
@ -377,6 +379,8 @@ struct sdw_slave_prop {
|
|||
* @dynamic_frame: Dynamic frame shape supported
|
||||
* @err_threshold: Number of times that software may retry sending a single
|
||||
* command
|
||||
* @mclk_freq: clock reference passed to SoundWire Master, in Hz.
|
||||
* @hw_disabled: if true, the Master is not functional, typically due to pin-mux
|
||||
*/
|
||||
struct sdw_master_prop {
|
||||
u32 revision;
|
||||
|
@ -391,6 +395,8 @@ struct sdw_master_prop {
|
|||
u32 default_col;
|
||||
bool dynamic_frame;
|
||||
u32 err_threshold;
|
||||
u32 mclk_freq;
|
||||
bool hw_disabled;
|
||||
};
|
||||
|
||||
int sdw_master_read_prop(struct sdw_bus *bus);
|
||||
|
@ -538,6 +544,7 @@ struct sdw_slave_ops {
|
|||
* @bus: Bus handle
|
||||
* @ops: Slave callback ops
|
||||
* @prop: Slave properties
|
||||
* @debugfs: Slave debugfs
|
||||
* @node: node for bus list
|
||||
* @port_ready: Port ready completion flag for each Slave port
|
||||
* @dev_num: Device Number assigned by Bus
|
||||
|
@ -549,6 +556,9 @@ struct sdw_slave {
|
|||
struct sdw_bus *bus;
|
||||
const struct sdw_slave_ops *ops;
|
||||
struct sdw_slave_prop prop;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs;
|
||||
#endif
|
||||
struct list_head node;
|
||||
struct completion *port_ready;
|
||||
u16 dev_num;
|
||||
|
@ -718,6 +728,7 @@ struct sdw_master_ops {
|
|||
* Bit set implies used number, bit clear implies unused number.
|
||||
* @bus_lock: bus lock
|
||||
* @msg_lock: message lock
|
||||
* @compute_params: points to Bus resource management implementation
|
||||
* @ops: Master callback ops
|
||||
* @port_ops: Master port callback ops
|
||||
* @params: Current bus parameters
|
||||
|
@ -725,6 +736,7 @@ struct sdw_master_ops {
|
|||
* @m_rt_list: List of Master instance of all stream(s) running on Bus. This
|
||||
* is used to compute and program bus bandwidth, clock, frame shape,
|
||||
* transport and port parameters
|
||||
* @debugfs: Bus debugfs
|
||||
* @defer_msg: Defer message
|
||||
* @clk_stop_timeout: Clock stop timeout computed
|
||||
* @bank_switch_timeout: Bank switch timeout computed
|
||||
|
@ -739,11 +751,15 @@ struct sdw_bus {
|
|||
DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
|
||||
struct mutex bus_lock;
|
||||
struct mutex msg_lock;
|
||||
int (*compute_params)(struct sdw_bus *bus);
|
||||
const struct sdw_master_ops *ops;
|
||||
const struct sdw_master_port_ops *port_ops;
|
||||
struct sdw_bus_params params;
|
||||
struct sdw_master_prop prop;
|
||||
struct list_head m_rt_list;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs;
|
||||
#endif
|
||||
struct sdw_defer defer_msg;
|
||||
unsigned int clk_stop_timeout;
|
||||
u32 bank_switch_timeout;
|
||||
|
@ -828,7 +844,7 @@ struct sdw_stream_params {
|
|||
* @m_rt_count: Count of Master runtime(s) in this stream
|
||||
*/
|
||||
struct sdw_stream_runtime {
|
||||
char *name;
|
||||
const char *name;
|
||||
struct sdw_stream_params params;
|
||||
enum sdw_stream_state state;
|
||||
enum sdw_stream_type type;
|
||||
|
@ -836,7 +852,7 @@ struct sdw_stream_runtime {
|
|||
int m_rt_count;
|
||||
};
|
||||
|
||||
struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name);
|
||||
struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name);
|
||||
void sdw_release_stream(struct sdw_stream_runtime *stream);
|
||||
int sdw_stream_add_master(struct sdw_bus *bus,
|
||||
struct sdw_stream_config *stream_config,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* struct sdw_intel_ops: Intel audio driver callback ops
|
||||
*
|
||||
* @config_stream: configure the stream with the hw_params
|
||||
* the first argument containing the context is mandatory
|
||||
*/
|
||||
struct sdw_intel_ops {
|
||||
int (*config_stream)(void *arg, void *substream,
|
||||
|
|
Loading…
Reference in New Issue