mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-17 22:05:08 +00:00
soundwire updates for v5.8-rc1
This contains sdw_master_device patches and other updates done by Intel folks. Details: - sdw_master_device to represent the master instances. - sysfs properties for sdw_master_device and sdw_slave. - Documentation update for TDM modes. - some code cleanup patches and odd updates. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAl7Gjb0ACgkQfBQHDyUj g0eCxQ//VrLecOXKp/UHgUXMxGGfOC/Bcg45zsuRQA18tHC0Ldx1JwRw4V57+5W7 tG980Z0DH94LEmt9Cuj9EvAoFTt5gH27SDvitvgc/S8BEOsD1XzsSIhwoQxdCt4O 6a8cSb+Oopm1efqXr72LTMIoPyQPhFcz61Y9qPmfomzKedTU1t4eZeUUnzsx9Ynz q1OE9/C/OqIhWBC5duBaM83tL6AVXH6lXW1hi53RjlIbSMdr6T/Mo0/9AAnKJv/t 32NvrFmJ8f+8rJsj3uRUKuSB3LxLoOM7yVhQ3NryzKZr3i2XA4Y0LaLd1KG2hzEB BO8zDIBeGkP/8FKFzyvIiBvF8bgxjbaaimEN984RfXbzlFXN49wfQAdgMI3I4Alu RjZl0s2tnJYAFicUdbw55e1JtXOuPAPtpokaugmRM2QbLta3dt00Tng9c0GVj/c6 Tp5plgW/tkRICCmcHC4UVEAfR79SfTuhVP6tMscAaj9R0LwV15hmDQkVwSIjLR3u n9NCWaeHrByRuyLyMvsbpFaGw07OKuRJwy6gKxGDpc3yUsPocX5TX5ap1DSfOt+3 96vUpTM0HI9+Rco1tlSHghJ97HaVkIbUNAQgmgaP1nF5ve4eI+NwTPyW4ax+Y+kW /AmkEvDoLnNcKLvAMRfq05KOxNcmP2gKhb4+XU9d0fMaJYWCgRg= =5MsU -----END PGP SIGNATURE----- Merge tag 'soundwire-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire into char-misc-next Vinod writes: soundwire updates for v5.8-rc1 This contains sdw_master_device patches and other updates done by Intel folks. Details: - sdw_master_device to represent the master instances. - sysfs properties for sdw_master_device and sdw_slave. - Documentation update for TDM modes. - some code cleanup patches and odd updates. * tag 'soundwire-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: soundwire: intel: use a single module soundwire: fix spelling mistake soundwire: fix trailing line in sysfs_slave.c soundwire: add Slave sysfs support soundwire: master: add sysfs support soundwire: disco: s/ch/channels/ soundwire: master: add runtime pm support soundwire: bus_type: add sdw_master_device support soundwire: bus: add unique bus id soundwire: bus_type: introduce sdw_slave_type and sdw_master_type soundwire: bus: rename sdw_bus_master_add/delete, add arguments soundwire: intel: (cosmetic) remove multiple superfluous "else" statements soundwire: (cosmetic) remove multiple superfluous "else" statements soundwire: qcom: Use IRQF_ONESHOT soundwire: bus: reduce verbosity on enumeration soundwire: debugfs: clarify SDPX license with GPL-2.0-only soundwire: slave: don't init debugfs on device registration error Documentation: SoundWire: clarify TDM mode support soundwire: qcom: fix error handling in probe soundwire: intel: use asoc_rtd_to_cpu() / asoc_rtd_to_codec() macro for DAI pointer
This commit is contained in:
commit
ddc0aef01a
23
Documentation/ABI/testing/sysfs-bus-soundwire-master
Normal file
23
Documentation/ABI/testing/sysfs-bus-soundwire-master
Normal file
@ -0,0 +1,23 @@
|
||||
What: /sys/bus/soundwire/devices/sdw-master-N/revision
|
||||
/sys/bus/soundwire/devices/sdw-master-N/clk_stop_modes
|
||||
/sys/bus/soundwire/devices/sdw-master-N/clk_freq
|
||||
/sys/bus/soundwire/devices/sdw-master-N/clk_gears
|
||||
/sys/bus/soundwire/devices/sdw-master-N/default_col
|
||||
/sys/bus/soundwire/devices/sdw-master-N/default_frame_rate
|
||||
/sys/bus/soundwire/devices/sdw-master-N/default_row
|
||||
/sys/bus/soundwire/devices/sdw-master-N/dynamic_shape
|
||||
/sys/bus/soundwire/devices/sdw-master-N/err_threshold
|
||||
/sys/bus/soundwire/devices/sdw-master-N/max_clk_freq
|
||||
|
||||
Date: April 2020
|
||||
|
||||
Contact: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Bard Liao <yung-chuan.liao@linux.intel.com>
|
||||
Vinod Koul <vkoul@kernel.org>
|
||||
|
||||
Description: SoundWire Master-N DisCo properties.
|
||||
These properties are defined by MIPI DisCo Specification
|
||||
for SoundWire. They define various properties of the Master
|
||||
and are used by the bus to configure the Master. clk_stop_modes
|
||||
is a bitmask for simplifications and combines the
|
||||
clock-stop-mode0 and clock-stop-mode1 properties.
|
91
Documentation/ABI/testing/sysfs-bus-soundwire-slave
Normal file
91
Documentation/ABI/testing/sysfs-bus-soundwire-slave
Normal file
@ -0,0 +1,91 @@
|
||||
What: /sys/bus/soundwire/devices/sdw:.../dev-properties/mipi_revision
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/wake_capable
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/test_mode_capable
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/clk_stop_mode1
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/simple_clk_stop_capable
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/clk_stop_timeout
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/ch_prep_timeout
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/reset_behave
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/high_PHY_capable
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/paging_support
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/bank_delay_support
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/p15_behave
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/master_count
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/source_ports
|
||||
/sys/bus/soundwire/devices/sdw:.../dev-properties/sink_ports
|
||||
|
||||
Date: May 2020
|
||||
|
||||
Contact: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Bard Liao <yung-chuan.liao@linux.intel.com>
|
||||
Vinod Koul <vkoul@kernel.org>
|
||||
|
||||
Description: SoundWire Slave DisCo properties.
|
||||
These properties are defined by MIPI DisCo Specification
|
||||
for SoundWire. They define various properties of the
|
||||
SoundWire Slave and are used by the bus to configure
|
||||
the Slave
|
||||
|
||||
|
||||
What: /sys/bus/soundwire/devices/sdw:.../dp0/max_word
|
||||
/sys/bus/soundwire/devices/sdw:.../dp0/min_word
|
||||
/sys/bus/soundwire/devices/sdw:.../dp0/words
|
||||
/sys/bus/soundwire/devices/sdw:.../dp0/BRA_flow_controlled
|
||||
/sys/bus/soundwire/devices/sdw:.../dp0/simple_ch_prep_sm
|
||||
/sys/bus/soundwire/devices/sdw:.../dp0/imp_def_interrupts
|
||||
|
||||
Date: May 2020
|
||||
|
||||
Contact: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Bard Liao <yung-chuan.liao@linux.intel.com>
|
||||
Vinod Koul <vkoul@kernel.org>
|
||||
|
||||
Description: SoundWire Slave Data Port-0 DisCo properties.
|
||||
These properties are defined by MIPI DisCo Specification
|
||||
for the SoundWire. They define various properties of the
|
||||
Data port 0 are used by the bus to configure the Data Port 0.
|
||||
|
||||
|
||||
What: /sys/bus/soundwire/devices/sdw:.../dpN_src/max_word
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/min_word
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/words
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/type
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/max_grouping
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/simple_ch_prep_sm
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/ch_prep_timeout
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/imp_def_interrupts
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/min_ch
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/max_ch
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/channels
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/ch_combinations
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/max_async_buffer
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/block_pack_mode
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_src/port_encoding
|
||||
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/max_word
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/min_word
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/words
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/type
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/max_grouping
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/simple_ch_prep_sm
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/ch_prep_timeout
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/imp_def_interrupts
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/min_ch
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/max_ch
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/channels
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/ch_combinations
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/max_async_buffer
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/block_pack_mode
|
||||
/sys/bus/soundwire/devices/sdw:.../dpN_sink/port_encoding
|
||||
|
||||
Date: May 2020
|
||||
|
||||
Contact: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Bard Liao <yung-chuan.liao@linux.intel.com>
|
||||
Vinod Koul <vkoul@kernel.org>
|
||||
|
||||
Description: SoundWire Slave Data Source/Sink Port-N DisCo properties.
|
||||
These properties are defined by MIPI DisCo Specification
|
||||
for SoundWire. They define various properties of the
|
||||
Source/Sink Data port N and are used by the bus to configure
|
||||
the Data Port N.
|
@ -75,8 +75,33 @@ Slaves are using single port. ::
|
||||
| (Data) |
|
||||
+---------------+
|
||||
|
||||
Example 4: Stereo Stream with L and R channels is rendered by
|
||||
Master. Both of the L and R channels are received by two different
|
||||
Slaves. Master and both Slaves are using single port handling
|
||||
L+R. Each Slave device processes the L + R data locally, typically
|
||||
based on static configuration or dynamic orientation, and may drive
|
||||
one or more speakers. ::
|
||||
|
||||
Example 4: Stereo Stream with L and R channel is rendered by two different
|
||||
+---------------+ Clock Signal +---------------+
|
||||
| Master +---------+------------------------+ Slave |
|
||||
| Interface | | | Interface |
|
||||
| | | | 1 |
|
||||
| | | Data Signal | |
|
||||
| L + R +---+------------------------------+ L + R |
|
||||
| (Data) | | | Data Direction | (Data) |
|
||||
+---------------+ | | +-------------> +---------------+
|
||||
| |
|
||||
| |
|
||||
| | +---------------+
|
||||
| +----------------------> | Slave |
|
||||
| | Interface |
|
||||
| | 2 |
|
||||
| | |
|
||||
+----------------------------> | L + R |
|
||||
| (Data) |
|
||||
+---------------+
|
||||
|
||||
Example 5: Stereo Stream with L and R channel is rendered by two different
|
||||
Ports of the Master and is received by only single Port of the Slave
|
||||
interface. ::
|
||||
|
||||
@ -101,7 +126,7 @@ interface. ::
|
||||
+--------------------+ | |
|
||||
+----------------+
|
||||
|
||||
Example 5: Stereo Stream with L and R channel is rendered by 2 Masters, each
|
||||
Example 6: Stereo Stream with L and R channel is rendered by 2 Masters, each
|
||||
rendering one channel, and is received by two different Slaves, each
|
||||
receiving one channel. Both Masters and both Slaves are using single port. ::
|
||||
|
||||
@ -123,12 +148,70 @@ receiving one channel. Both Masters and both Slaves are using single port. ::
|
||||
| (Data) | Data Direction | (Data) |
|
||||
+---------------+ +-----------------------> +---------------+
|
||||
|
||||
Note: In multi-link cases like above, to lock, one would acquire a global
|
||||
Example 7: Stereo Stream with L and R channel is rendered by 2
|
||||
Masters, each rendering both channels. Each Slave receives L + R. This
|
||||
is the same application as Example 4 but with Slaves placed on
|
||||
separate links. ::
|
||||
|
||||
+---------------+ Clock Signal +---------------+
|
||||
| Master +----------------------------------+ Slave |
|
||||
| Interface | | Interface |
|
||||
| 1 | | 1 |
|
||||
| | Data Signal | |
|
||||
| L + R +----------------------------------+ L + R |
|
||||
| (Data) | Data Direction | (Data) |
|
||||
+---------------+ +-----------------------> +---------------+
|
||||
|
||||
+---------------+ Clock Signal +---------------+
|
||||
| Master +----------------------------------+ Slave |
|
||||
| Interface | | Interface |
|
||||
| 2 | | 2 |
|
||||
| | Data Signal | |
|
||||
| L + R +----------------------------------+ L + R |
|
||||
| (Data) | Data Direction | (Data) |
|
||||
+---------------+ +-----------------------> +---------------+
|
||||
|
||||
Example 8: 4-channel Stream is rendered by 2 Masters, each rendering a
|
||||
2 channels. Each Slave receives 2 channels. ::
|
||||
|
||||
+---------------+ Clock Signal +---------------+
|
||||
| Master +----------------------------------+ Slave |
|
||||
| Interface | | Interface |
|
||||
| 1 | | 1 |
|
||||
| | Data Signal | |
|
||||
| L1 + R1 +----------------------------------+ L1 + R1 |
|
||||
| (Data) | Data Direction | (Data) |
|
||||
+---------------+ +-----------------------> +---------------+
|
||||
|
||||
+---------------+ Clock Signal +---------------+
|
||||
| Master +----------------------------------+ Slave |
|
||||
| Interface | | Interface |
|
||||
| 2 | | 2 |
|
||||
| | Data Signal | |
|
||||
| L2 + R2 +----------------------------------+ L2 + R2 |
|
||||
| (Data) | Data Direction | (Data) |
|
||||
+---------------+ +-----------------------> +---------------+
|
||||
|
||||
Note1: In multi-link cases like above, to lock, one would acquire a global
|
||||
lock and then go on locking bus instances. But, in this case the caller
|
||||
framework(ASoC DPCM) guarantees that stream operations on a card are
|
||||
always serialized. So, there is no race condition and hence no need for
|
||||
global lock.
|
||||
|
||||
Note2: A Slave device may be configured to receive all channels
|
||||
transmitted on a link for a given Stream (Example 4) or just a subset
|
||||
of the data (Example 3). The configuration of the Slave device is not
|
||||
handled by a SoundWire subsystem API, but instead by the
|
||||
snd_soc_dai_set_tdm_slot() API. The platform or machine driver will
|
||||
typically configure which of the slots are used. For Example 4, the
|
||||
same slots would be used by all Devices, while for Example 3 the Slave
|
||||
Device1 would use e.g. Slot 0 and Slave device2 slot 1.
|
||||
|
||||
Note3: Multiple Sink ports can extract the same information for the
|
||||
same bitSlots in the SoundWire frame, however multiple Source ports
|
||||
shall be configured with different bitSlot configurations. This is the
|
||||
same limitation as with I2S/PCM TDM usages.
|
||||
|
||||
SoundWire Stream Management flow
|
||||
================================
|
||||
|
||||
|
@ -101,10 +101,11 @@ Following is the Bus API to register the SoundWire Bus:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int sdw_add_bus_master(struct sdw_bus *bus)
|
||||
int sdw_bus_master_add(struct sdw_bus *bus,
|
||||
struct device *parent,
|
||||
struct fwnode_handle)
|
||||
{
|
||||
if (!bus->dev)
|
||||
return -ENODEV;
|
||||
sdw_master_device_add(bus, parent, fwnode);
|
||||
|
||||
mutex_init(&bus->lock);
|
||||
INIT_LIST_HEAD(&bus->slaves);
|
||||
|
@ -4,7 +4,8 @@
|
||||
#
|
||||
|
||||
#Bus Objs
|
||||
soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o
|
||||
soundwire-bus-objs := bus_type.o bus.o master.o slave.o mipi_disco.o stream.o \
|
||||
sysfs_slave.o sysfs_slave_dpn.o
|
||||
obj-$(CONFIG_SOUNDWIRE) += soundwire-bus.o
|
||||
|
||||
ifdef CONFIG_DEBUG_FS
|
||||
@ -16,12 +17,9 @@ soundwire-cadence-objs := cadence_master.o
|
||||
obj-$(CONFIG_SOUNDWIRE_CADENCE) += soundwire-cadence.o
|
||||
|
||||
#Intel driver
|
||||
soundwire-intel-objs := intel.o
|
||||
soundwire-intel-objs := intel.o intel_init.o
|
||||
obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o
|
||||
|
||||
soundwire-intel-init-objs := intel_init.o
|
||||
obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel-init.o
|
||||
|
||||
#Qualcomm driver
|
||||
soundwire-qcom-objs := qcom.o
|
||||
obj-$(CONFIG_SOUNDWIRE_QCOM) += soundwire-qcom.o
|
||||
|
@ -8,24 +8,54 @@
|
||||
#include <linux/soundwire/sdw_registers.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include "bus.h"
|
||||
#include "sysfs_local.h"
|
||||
|
||||
static DEFINE_IDA(sdw_ida);
|
||||
|
||||
static int sdw_get_id(struct sdw_bus *bus)
|
||||
{
|
||||
int rc = ida_alloc(&sdw_ida, GFP_KERNEL);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
bus->id = rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sdw_add_bus_master() - add a bus Master instance
|
||||
* sdw_bus_master_add() - add a bus Master instance
|
||||
* @bus: bus instance
|
||||
* @parent: parent device
|
||||
* @fwnode: firmware node handle
|
||||
*
|
||||
* Initializes the bus instance, read properties and create child
|
||||
* devices.
|
||||
*/
|
||||
int sdw_add_bus_master(struct sdw_bus *bus)
|
||||
int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
|
||||
struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct sdw_master_prop *prop = NULL;
|
||||
int ret;
|
||||
|
||||
if (!bus->dev) {
|
||||
pr_err("SoundWire bus has no device\n");
|
||||
if (!parent) {
|
||||
pr_err("SoundWire parent device is not set\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = sdw_get_id(bus);
|
||||
if (ret) {
|
||||
dev_err(parent, "Failed to get bus id\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sdw_master_device_add(bus, parent, fwnode);
|
||||
if (ret) {
|
||||
dev_err(parent, "Failed to add master device at link %d\n",
|
||||
bus->link_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!bus->ops) {
|
||||
dev_err(bus->dev, "SoundWire Bus ops are not set\n");
|
||||
return -EINVAL;
|
||||
@ -107,7 +137,7 @@ int sdw_add_bus_master(struct sdw_bus *bus)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sdw_add_bus_master);
|
||||
EXPORT_SYMBOL(sdw_bus_master_add);
|
||||
|
||||
static int sdw_delete_slave(struct device *dev, void *data)
|
||||
{
|
||||
@ -131,18 +161,20 @@ static int sdw_delete_slave(struct device *dev, void *data)
|
||||
}
|
||||
|
||||
/**
|
||||
* sdw_delete_bus_master() - delete the bus master instance
|
||||
* sdw_bus_master_delete() - delete the bus master instance
|
||||
* @bus: bus to be deleted
|
||||
*
|
||||
* Remove the instance, delete the child devices.
|
||||
*/
|
||||
void sdw_delete_bus_master(struct sdw_bus *bus)
|
||||
void sdw_bus_master_delete(struct sdw_bus *bus)
|
||||
{
|
||||
device_for_each_child(bus->dev, NULL, sdw_delete_slave);
|
||||
sdw_master_device_del(bus);
|
||||
|
||||
sdw_bus_debugfs_exit(bus);
|
||||
ida_free(&sdw_ida, bus->id);
|
||||
}
|
||||
EXPORT_SYMBOL(sdw_delete_bus_master);
|
||||
EXPORT_SYMBOL(sdw_bus_master_delete);
|
||||
|
||||
/*
|
||||
* SDW IO Calls
|
||||
@ -284,9 +316,10 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
|
||||
msg->flags = flags;
|
||||
msg->buf = buf;
|
||||
|
||||
if (addr < SDW_REG_NO_PAGE) { /* no paging area */
|
||||
if (addr < SDW_REG_NO_PAGE) /* no paging area */
|
||||
return 0;
|
||||
} else if (addr >= SDW_REG_MAX) { /* illegal addr */
|
||||
|
||||
if (addr >= SDW_REG_MAX) { /* illegal addr */
|
||||
pr_err("SDW: Invalid address %x passed\n", addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -306,7 +339,9 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
|
||||
if (!slave) {
|
||||
pr_err("SDW: No slave for paging addr\n");
|
||||
return -EINVAL;
|
||||
} else if (!slave->prop.paging_support) {
|
||||
}
|
||||
|
||||
if (!slave->prop.paging_support) {
|
||||
dev_err(&slave->dev,
|
||||
"address %x needs paging but no support\n", addr);
|
||||
return -EINVAL;
|
||||
@ -375,8 +410,8 @@ sdw_bread_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr)
|
||||
ret = sdw_transfer(bus, &msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else
|
||||
return buf;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -471,8 +506,8 @@ int sdw_read(struct sdw_slave *slave, u32 addr)
|
||||
ret = sdw_nread(slave, addr, 1, &buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else
|
||||
return buf;
|
||||
|
||||
return buf;
|
||||
}
|
||||
EXPORT_SYMBOL(sdw_read);
|
||||
|
||||
@ -563,9 +598,9 @@ static int sdw_assign_device_num(struct sdw_slave *slave)
|
||||
}
|
||||
|
||||
if (!new_device)
|
||||
dev_info(slave->bus->dev,
|
||||
"Slave already registered, reusing dev_num:%d\n",
|
||||
slave->dev_num);
|
||||
dev_dbg(slave->bus->dev,
|
||||
"Slave already registered, reusing dev_num:%d\n",
|
||||
slave->dev_num);
|
||||
|
||||
/* Clear the slave->dev_num to transfer message on device 0 */
|
||||
dev_num = slave->dev_num;
|
||||
|
@ -19,6 +19,9 @@ static inline int sdw_acpi_find_slaves(struct sdw_bus *bus)
|
||||
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);
|
||||
int sdw_master_device_add(struct sdw_bus *bus, struct device *parent,
|
||||
struct fwnode_handle *fwnode);
|
||||
int sdw_master_device_del(struct sdw_bus *bus);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void sdw_bus_debugfs_init(struct sdw_bus *bus);
|
||||
@ -172,5 +175,6 @@ sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
|
||||
#define SDW_UNATTACH_REQUEST_MASTER_RESET BIT(0)
|
||||
|
||||
void sdw_clear_slave_status(struct sdw_bus *bus, u32 request);
|
||||
int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size);
|
||||
|
||||
#endif /* __SDW_BUS_H */
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include "bus.h"
|
||||
#include "sysfs_local.h"
|
||||
|
||||
/**
|
||||
* sdw_get_device_id - find the matching SoundWire device id
|
||||
@ -33,10 +34,17 @@ sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv)
|
||||
|
||||
static int sdw_bus_match(struct device *dev, struct device_driver *ddrv)
|
||||
{
|
||||
struct sdw_slave *slave = dev_to_sdw_dev(dev);
|
||||
struct sdw_driver *drv = drv_to_sdw_driver(ddrv);
|
||||
struct sdw_slave *slave;
|
||||
struct sdw_driver *drv;
|
||||
int ret = 0;
|
||||
|
||||
return !!sdw_get_device_id(slave, drv);
|
||||
if (is_sdw_slave(dev)) {
|
||||
slave = dev_to_sdw_dev(dev);
|
||||
drv = drv_to_sdw_driver(ddrv);
|
||||
|
||||
ret = !!sdw_get_device_id(slave, drv);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size)
|
||||
@ -47,7 +55,7 @@ int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size)
|
||||
slave->id.mfg_id, slave->id.part_id);
|
||||
}
|
||||
|
||||
static int sdw_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
int sdw_slave_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct sdw_slave *slave = dev_to_sdw_dev(dev);
|
||||
char modalias[32];
|
||||
@ -63,7 +71,6 @@ static int sdw_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
struct bus_type sdw_bus_type = {
|
||||
.name = "soundwire",
|
||||
.match = sdw_bus_match,
|
||||
.uevent = sdw_uevent,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(sdw_bus_type);
|
||||
|
||||
@ -98,6 +105,11 @@ static int sdw_drv_probe(struct device *dev)
|
||||
if (slave->ops && slave->ops->read_prop)
|
||||
slave->ops->read_prop(slave);
|
||||
|
||||
/* init the sysfs as we have properties now */
|
||||
ret = sdw_slave_sysfs_init(slave);
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "Slave sysfs init failed:%d\n", ret);
|
||||
|
||||
/*
|
||||
* Check for valid clk_stop_timeout, use DisCo worst case value of
|
||||
* 300ms
|
||||
|
@ -407,7 +407,9 @@ cdns_fill_msg_resp(struct sdw_cdns *cdns,
|
||||
if (nack) {
|
||||
dev_err_ratelimited(cdns->dev, "Msg NACKed for Slave %d\n", msg->dev_num);
|
||||
return SDW_CMD_FAIL;
|
||||
} else if (no_ack) {
|
||||
}
|
||||
|
||||
if (no_ack) {
|
||||
dev_dbg_ratelimited(cdns->dev, "Msg ignored for Slave %d\n", msg->dev_num);
|
||||
return SDW_CMD_IGNORED;
|
||||
}
|
||||
@ -520,7 +522,9 @@ cdns_program_scp_addr(struct sdw_cdns *cdns, struct sdw_msg *msg)
|
||||
dev_err_ratelimited(cdns->dev,
|
||||
"SCP_addrpage NACKed for Slave %d\n", msg->dev_num);
|
||||
return SDW_CMD_FAIL;
|
||||
} else if (no_ack) {
|
||||
}
|
||||
|
||||
if (no_ack) {
|
||||
dev_dbg_ratelimited(cdns->dev,
|
||||
"SCP_addrpage ignored for Slave %d\n", msg->dev_num);
|
||||
return SDW_CMD_IGNORED;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright(c) 2017-2019 Intel Corporation.
|
||||
|
||||
#include <linux/device.h>
|
||||
|
@ -669,11 +669,11 @@ static int sdw_stream_setup(struct snd_pcm_substream *substream,
|
||||
|
||||
/* Set stream pointer on all CODEC DAIs */
|
||||
for (i = 0; i < rtd->num_codecs; i++) {
|
||||
ret = snd_soc_dai_set_sdw_stream(rtd->codec_dais[i], sdw_stream,
|
||||
ret = snd_soc_dai_set_sdw_stream(asoc_rtd_to_codec(rtd, i), sdw_stream,
|
||||
substream->stream);
|
||||
if (ret < 0) {
|
||||
dev_err(dai->dev, "failed to set stream pointer on codec dai %s",
|
||||
rtd->codec_dais[i]->name);
|
||||
asoc_rtd_to_codec(rtd, i)->name);
|
||||
goto release_stream;
|
||||
}
|
||||
}
|
||||
@ -1099,7 +1099,6 @@ static int intel_probe(struct platform_device *pdev)
|
||||
sdw->cdns.registers = sdw->link_res->registers;
|
||||
sdw->cdns.instance = sdw->instance;
|
||||
sdw->cdns.msg_count = 0;
|
||||
sdw->cdns.bus.dev = &pdev->dev;
|
||||
sdw->cdns.bus.link_id = pdev->id;
|
||||
|
||||
sdw_cdns_probe(&sdw->cdns);
|
||||
@ -1110,9 +1109,9 @@ static int intel_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, sdw);
|
||||
|
||||
ret = sdw_add_bus_master(&sdw->cdns.bus);
|
||||
ret = sdw_bus_master_add(&sdw->cdns.bus, &pdev->dev, pdev->dev.fwnode);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "sdw_add_bus_master fail: %d\n", ret);
|
||||
dev_err(&pdev->dev, "sdw_bus_master_add fail: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1173,7 +1172,7 @@ err_interrupt:
|
||||
sdw_cdns_enable_interrupt(&sdw->cdns, false);
|
||||
free_irq(sdw->link_res->irq, sdw);
|
||||
err_init:
|
||||
sdw_delete_bus_master(&sdw->cdns.bus);
|
||||
sdw_bus_master_delete(&sdw->cdns.bus);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1189,7 +1188,7 @@ static int intel_remove(struct platform_device *pdev)
|
||||
free_irq(sdw->link_res->irq, sdw);
|
||||
snd_soc_unregister_component(sdw->cdns.dev);
|
||||
}
|
||||
sdw_delete_bus_master(&sdw->cdns.bus);
|
||||
sdw_bus_master_delete(&sdw->cdns.bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -86,7 +86,9 @@ static struct sdw_intel_ctx
|
||||
dev_err(&adev->dev, "Link count %d exceeds max %d\n",
|
||||
count, SDW_MAX_LINKS);
|
||||
return NULL;
|
||||
} else if (!count) {
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
dev_warn(&adev->dev, "No SoundWire links detected\n");
|
||||
return NULL;
|
||||
}
|
||||
|
172
drivers/soundwire/master.c
Normal file
172
drivers/soundwire/master.c
Normal file
@ -0,0 +1,172 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright(c) 2019-2020 Intel Corporation.
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include "bus.h"
|
||||
|
||||
/*
|
||||
* The sysfs for properties reflects the MIPI description as given
|
||||
* in the MIPI DisCo spec
|
||||
*
|
||||
* Base file is:
|
||||
* sdw-master-N
|
||||
* |---- revision
|
||||
* |---- clk_stop_modes
|
||||
* |---- max_clk_freq
|
||||
* |---- clk_freq
|
||||
* |---- clk_gears
|
||||
* |---- default_row
|
||||
* |---- default_col
|
||||
* |---- dynamic_shape
|
||||
* |---- err_threshold
|
||||
*/
|
||||
|
||||
#define sdw_master_attr(field, format_string) \
|
||||
static ssize_t field##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct sdw_master_device *md = dev_to_sdw_master_device(dev); \
|
||||
return sprintf(buf, format_string, md->bus->prop.field); \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(field)
|
||||
|
||||
sdw_master_attr(revision, "0x%x\n");
|
||||
sdw_master_attr(clk_stop_modes, "0x%x\n");
|
||||
sdw_master_attr(max_clk_freq, "%d\n");
|
||||
sdw_master_attr(default_row, "%d\n");
|
||||
sdw_master_attr(default_col, "%d\n");
|
||||
sdw_master_attr(default_frame_rate, "%d\n");
|
||||
sdw_master_attr(dynamic_frame, "%d\n");
|
||||
sdw_master_attr(err_threshold, "%d\n");
|
||||
|
||||
static ssize_t clock_frequencies_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct sdw_master_device *md = dev_to_sdw_master_device(dev);
|
||||
ssize_t size = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < md->bus->prop.num_clk_freq; i++)
|
||||
size += sprintf(buf + size, "%8d ",
|
||||
md->bus->prop.clk_freq[i]);
|
||||
size += sprintf(buf + size, "\n");
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RO(clock_frequencies);
|
||||
|
||||
static ssize_t clock_gears_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct sdw_master_device *md = dev_to_sdw_master_device(dev);
|
||||
ssize_t size = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < md->bus->prop.num_clk_gears; i++)
|
||||
size += sprintf(buf + size, "%8d ",
|
||||
md->bus->prop.clk_gears[i]);
|
||||
size += sprintf(buf + size, "\n");
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RO(clock_gears);
|
||||
|
||||
static struct attribute *master_node_attrs[] = {
|
||||
&dev_attr_revision.attr,
|
||||
&dev_attr_clk_stop_modes.attr,
|
||||
&dev_attr_max_clk_freq.attr,
|
||||
&dev_attr_default_row.attr,
|
||||
&dev_attr_default_col.attr,
|
||||
&dev_attr_default_frame_rate.attr,
|
||||
&dev_attr_dynamic_frame.attr,
|
||||
&dev_attr_err_threshold.attr,
|
||||
&dev_attr_clock_frequencies.attr,
|
||||
&dev_attr_clock_gears.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(master_node);
|
||||
|
||||
static void sdw_master_device_release(struct device *dev)
|
||||
{
|
||||
struct sdw_master_device *md = dev_to_sdw_master_device(dev);
|
||||
|
||||
kfree(md);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops master_dev_pm = {
|
||||
SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend,
|
||||
pm_generic_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
struct device_type sdw_master_type = {
|
||||
.name = "soundwire_master",
|
||||
.release = sdw_master_device_release,
|
||||
.pm = &master_dev_pm,
|
||||
};
|
||||
|
||||
/**
|
||||
* sdw_master_device_add() - create a Linux Master Device representation.
|
||||
* @bus: SDW bus instance
|
||||
* @parent: parent device
|
||||
* @fwnode: firmware node handle
|
||||
*/
|
||||
int sdw_master_device_add(struct sdw_bus *bus, struct device *parent,
|
||||
struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct sdw_master_device *md;
|
||||
int ret;
|
||||
|
||||
if (!parent)
|
||||
return -EINVAL;
|
||||
|
||||
md = kzalloc(sizeof(*md), GFP_KERNEL);
|
||||
if (!md)
|
||||
return -ENOMEM;
|
||||
|
||||
md->dev.bus = &sdw_bus_type;
|
||||
md->dev.type = &sdw_master_type;
|
||||
md->dev.parent = parent;
|
||||
md->dev.groups = master_node_groups;
|
||||
md->dev.of_node = parent->of_node;
|
||||
md->dev.fwnode = fwnode;
|
||||
md->dev.dma_mask = parent->dma_mask;
|
||||
|
||||
dev_set_name(&md->dev, "sdw-master-%d", bus->id);
|
||||
|
||||
ret = device_register(&md->dev);
|
||||
if (ret) {
|
||||
dev_err(parent, "Failed to add master: ret %d\n", ret);
|
||||
/*
|
||||
* On err, don't free but drop ref as this will be freed
|
||||
* when release method is invoked.
|
||||
*/
|
||||
put_device(&md->dev);
|
||||
goto device_register_err;
|
||||
}
|
||||
|
||||
/* add shortcuts to improve code readability/compactness */
|
||||
md->bus = bus;
|
||||
bus->dev = &md->dev;
|
||||
bus->md = md;
|
||||
|
||||
device_register_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* sdw_master_device_del() - delete a Linux Master Device representation.
|
||||
* @bus: bus handle
|
||||
*
|
||||
* This function is the dual of sdw_master_device_add()
|
||||
*/
|
||||
int sdw_master_device_del(struct sdw_bus *bus)
|
||||
{
|
||||
device_unregister(bus->dev);
|
||||
|
||||
return 0;
|
||||
}
|
@ -231,16 +231,17 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
|
||||
|
||||
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,
|
||||
sizeof(*dpn[i].ch),
|
||||
dpn[i].num_channels = nval;
|
||||
dpn[i].channels = devm_kcalloc(&slave->dev,
|
||||
dpn[i].num_channels,
|
||||
sizeof(*dpn[i].channels),
|
||||
GFP_KERNEL);
|
||||
if (!dpn[i].ch)
|
||||
if (!dpn[i].channels)
|
||||
return -ENOMEM;
|
||||
|
||||
fwnode_property_read_u32_array(node,
|
||||
"mipi-sdw-channel-number-list",
|
||||
dpn[i].ch, dpn[i].num_ch);
|
||||
dpn[i].channels, dpn[i].num_channels);
|
||||
}
|
||||
|
||||
nval = fwnode_property_count_u32(node, "mipi-sdw-channel-combination-list");
|
||||
|
@ -765,12 +765,16 @@ static int qcom_swrm_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ctrl->irq = of_irq_get(dev->of_node, 0);
|
||||
if (ctrl->irq < 0)
|
||||
return ctrl->irq;
|
||||
if (ctrl->irq < 0) {
|
||||
ret = ctrl->irq;
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
ctrl->hclk = devm_clk_get(dev, "iface");
|
||||
if (IS_ERR(ctrl->hclk))
|
||||
return PTR_ERR(ctrl->hclk);
|
||||
if (IS_ERR(ctrl->hclk)) {
|
||||
ret = PTR_ERR(ctrl->hclk);
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
clk_prepare_enable(ctrl->hclk);
|
||||
|
||||
@ -780,14 +784,13 @@ static int qcom_swrm_probe(struct platform_device *pdev)
|
||||
mutex_init(&ctrl->port_lock);
|
||||
INIT_WORK(&ctrl->slave_work, qcom_swrm_slave_wq);
|
||||
|
||||
ctrl->bus.dev = dev;
|
||||
ctrl->bus.ops = &qcom_swrm_ops;
|
||||
ctrl->bus.port_ops = &qcom_swrm_port_ops;
|
||||
ctrl->bus.compute_params = &qcom_swrm_compute_params;
|
||||
|
||||
ret = qcom_swrm_get_port_config(ctrl);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_clk;
|
||||
|
||||
params = &ctrl->bus.params;
|
||||
params->max_dr_freq = DEFAULT_CLK_FREQ;
|
||||
@ -810,32 +813,37 @@ static int qcom_swrm_probe(struct platform_device *pdev)
|
||||
|
||||
ret = devm_request_threaded_irq(dev, ctrl->irq, NULL,
|
||||
qcom_swrm_irq_handler,
|
||||
IRQF_TRIGGER_RISING,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_ONESHOT,
|
||||
"soundwire", ctrl);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to request soundwire irq\n");
|
||||
goto err;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
ret = sdw_add_bus_master(&ctrl->bus);
|
||||
ret = sdw_bus_master_add(&ctrl->bus, dev, dev->fwnode);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register Soundwire controller (%d)\n",
|
||||
ret);
|
||||
goto err;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
qcom_swrm_init(ctrl);
|
||||
ret = qcom_swrm_register_dais(ctrl);
|
||||
if (ret)
|
||||
goto err;
|
||||
goto err_master_add;
|
||||
|
||||
dev_info(dev, "Qualcomm Soundwire controller v%x.%x.%x Registered\n",
|
||||
(ctrl->version >> 24) & 0xff, (ctrl->version >> 16) & 0xff,
|
||||
ctrl->version & 0xffff);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
|
||||
err_master_add:
|
||||
sdw_bus_master_delete(&ctrl->bus);
|
||||
err_clk:
|
||||
clk_disable_unprepare(ctrl->hclk);
|
||||
err_init:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -843,7 +851,7 @@ static int qcom_swrm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
sdw_delete_bus_master(&ctrl->bus);
|
||||
sdw_bus_master_delete(&ctrl->bus);
|
||||
clk_disable_unprepare(ctrl->hclk);
|
||||
|
||||
return 0;
|
||||
|
@ -14,6 +14,12 @@ static void sdw_slave_release(struct device *dev)
|
||||
kfree(slave);
|
||||
}
|
||||
|
||||
struct device_type sdw_slave_type = {
|
||||
.name = "sdw_slave",
|
||||
.release = sdw_slave_release,
|
||||
.uevent = sdw_slave_uevent,
|
||||
};
|
||||
|
||||
static int sdw_slave_add(struct sdw_bus *bus,
|
||||
struct sdw_slave_id *id, struct fwnode_handle *fwnode)
|
||||
{
|
||||
@ -41,9 +47,9 @@ static int sdw_slave_add(struct sdw_bus *bus,
|
||||
id->class_id, id->unique_id);
|
||||
}
|
||||
|
||||
slave->dev.release = sdw_slave_release;
|
||||
slave->dev.bus = &sdw_bus_type;
|
||||
slave->dev.of_node = of_node_get(to_of_node(fwnode));
|
||||
slave->dev.type = &sdw_slave_type;
|
||||
slave->bus = bus;
|
||||
slave->status = SDW_SLAVE_UNATTACHED;
|
||||
init_completion(&slave->enumeration_complete);
|
||||
@ -68,6 +74,8 @@ static int sdw_slave_add(struct sdw_bus *bus,
|
||||
list_del(&slave->node);
|
||||
mutex_unlock(&bus->bus_lock);
|
||||
put_device(&slave->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
sdw_slave_debugfs_init(slave);
|
||||
|
||||
|
14
drivers/soundwire/sysfs_local.h
Normal file
14
drivers/soundwire/sysfs_local.h
Normal file
@ -0,0 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright(c) 2015-2020 Intel Corporation. */
|
||||
|
||||
#ifndef __SDW_SYSFS_LOCAL_H
|
||||
#define __SDW_SYSFS_LOCAL_H
|
||||
|
||||
/*
|
||||
* SDW sysfs APIs -
|
||||
*/
|
||||
|
||||
int sdw_slave_sysfs_init(struct sdw_slave *slave);
|
||||
int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave);
|
||||
|
||||
#endif /* __SDW_SYSFS_LOCAL_H */
|
214
drivers/soundwire/sysfs_slave.c
Normal file
214
drivers/soundwire/sysfs_slave.c
Normal file
@ -0,0 +1,214 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright(c) 2015-2020 Intel Corporation.
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include "bus.h"
|
||||
#include "sysfs_local.h"
|
||||
|
||||
/*
|
||||
* Slave sysfs
|
||||
*/
|
||||
|
||||
/*
|
||||
* The sysfs for Slave reflects the MIPI description as given
|
||||
* in the MIPI DisCo spec
|
||||
*
|
||||
* Base file is device
|
||||
* |---- modalias
|
||||
* |---- dev-properties
|
||||
* |---- mipi_revision
|
||||
* |---- wake_capable
|
||||
* |---- test_mode_capable
|
||||
* |---- clk_stop_mode1
|
||||
* |---- simple_clk_stop_capable
|
||||
* |---- clk_stop_timeout
|
||||
* |---- ch_prep_timeout
|
||||
* |---- reset_behave
|
||||
* |---- high_PHY_capable
|
||||
* |---- paging_support
|
||||
* |---- bank_delay_support
|
||||
* |---- p15_behave
|
||||
* |---- master_count
|
||||
* |---- source_ports
|
||||
* |---- sink_ports
|
||||
* |---- dp0
|
||||
* |---- max_word
|
||||
* |---- min_word
|
||||
* |---- words
|
||||
* |---- BRA_flow_controlled
|
||||
* |---- simple_ch_prep_sm
|
||||
* |---- imp_def_interrupts
|
||||
* |---- dpN_<sink/src>
|
||||
* |---- max_word
|
||||
* |---- min_word
|
||||
* |---- words
|
||||
* |---- type
|
||||
* |---- max_grouping
|
||||
* |---- simple_ch_prep_sm
|
||||
* |---- ch_prep_timeout
|
||||
* |---- imp_def_interrupts
|
||||
* |---- min_ch
|
||||
* |---- max_ch
|
||||
* |---- channels
|
||||
* |---- ch_combinations
|
||||
* |---- max_async_buffer
|
||||
* |---- block_pack_mode
|
||||
* |---- port_encoding
|
||||
*
|
||||
*/
|
||||
|
||||
#define sdw_slave_attr(field, format_string) \
|
||||
static ssize_t field##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct sdw_slave *slave = dev_to_sdw_dev(dev); \
|
||||
return sprintf(buf, format_string, slave->prop.field); \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(field)
|
||||
|
||||
sdw_slave_attr(mipi_revision, "0x%x\n");
|
||||
sdw_slave_attr(wake_capable, "%d\n");
|
||||
sdw_slave_attr(test_mode_capable, "%d\n");
|
||||
sdw_slave_attr(clk_stop_mode1, "%d\n");
|
||||
sdw_slave_attr(simple_clk_stop_capable, "%d\n");
|
||||
sdw_slave_attr(clk_stop_timeout, "%d\n");
|
||||
sdw_slave_attr(ch_prep_timeout, "%d\n");
|
||||
sdw_slave_attr(reset_behave, "%d\n");
|
||||
sdw_slave_attr(high_PHY_capable, "%d\n");
|
||||
sdw_slave_attr(paging_support, "%d\n");
|
||||
sdw_slave_attr(bank_delay_support, "%d\n");
|
||||
sdw_slave_attr(p15_behave, "%d\n");
|
||||
sdw_slave_attr(master_count, "%d\n");
|
||||
sdw_slave_attr(source_ports, "0x%x\n");
|
||||
sdw_slave_attr(sink_ports, "0x%x\n");
|
||||
|
||||
static ssize_t modalias_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct sdw_slave *slave = dev_to_sdw_dev(dev);
|
||||
|
||||
return sdw_slave_modalias(slave, buf, 256);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct attribute *slave_attrs[] = {
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(slave);
|
||||
|
||||
static struct attribute *slave_dev_attrs[] = {
|
||||
&dev_attr_mipi_revision.attr,
|
||||
&dev_attr_wake_capable.attr,
|
||||
&dev_attr_test_mode_capable.attr,
|
||||
&dev_attr_clk_stop_mode1.attr,
|
||||
&dev_attr_simple_clk_stop_capable.attr,
|
||||
&dev_attr_clk_stop_timeout.attr,
|
||||
&dev_attr_ch_prep_timeout.attr,
|
||||
&dev_attr_reset_behave.attr,
|
||||
&dev_attr_high_PHY_capable.attr,
|
||||
&dev_attr_paging_support.attr,
|
||||
&dev_attr_bank_delay_support.attr,
|
||||
&dev_attr_p15_behave.attr,
|
||||
&dev_attr_master_count.attr,
|
||||
&dev_attr_source_ports.attr,
|
||||
&dev_attr_sink_ports.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* we don't use ATTRIBUTES_GROUP here since we want to add a subdirectory
|
||||
* for device-level properties
|
||||
*/
|
||||
static struct attribute_group sdw_slave_dev_attr_group = {
|
||||
.attrs = slave_dev_attrs,
|
||||
.name = "dev-properties",
|
||||
};
|
||||
|
||||
/*
|
||||
* DP0 sysfs
|
||||
*/
|
||||
|
||||
#define sdw_dp0_attr(field, format_string) \
|
||||
static ssize_t field##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct sdw_slave *slave = dev_to_sdw_dev(dev); \
|
||||
return sprintf(buf, format_string, slave->prop.dp0_prop->field);\
|
||||
} \
|
||||
static DEVICE_ATTR_RO(field)
|
||||
|
||||
sdw_dp0_attr(max_word, "%d\n");
|
||||
sdw_dp0_attr(min_word, "%d\n");
|
||||
sdw_dp0_attr(BRA_flow_controlled, "%d\n");
|
||||
sdw_dp0_attr(simple_ch_prep_sm, "%d\n");
|
||||
sdw_dp0_attr(imp_def_interrupts, "0x%x\n");
|
||||
|
||||
static ssize_t words_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct sdw_slave *slave = dev_to_sdw_dev(dev);
|
||||
ssize_t size = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < slave->prop.dp0_prop->num_words; i++)
|
||||
size += sprintf(buf + size, "%d ",
|
||||
slave->prop.dp0_prop->words[i]);
|
||||
size += sprintf(buf + size, "\n");
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RO(words);
|
||||
|
||||
static struct attribute *dp0_attrs[] = {
|
||||
&dev_attr_max_word.attr,
|
||||
&dev_attr_min_word.attr,
|
||||
&dev_attr_words.attr,
|
||||
&dev_attr_BRA_flow_controlled.attr,
|
||||
&dev_attr_simple_ch_prep_sm.attr,
|
||||
&dev_attr_imp_def_interrupts.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* we don't use ATTRIBUTES_GROUP here since we want to add a subdirectory
|
||||
* for dp0-level properties
|
||||
*/
|
||||
static const struct attribute_group dp0_group = {
|
||||
.attrs = dp0_attrs,
|
||||
.name = "dp0",
|
||||
};
|
||||
|
||||
int sdw_slave_sysfs_init(struct sdw_slave *slave)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = devm_device_add_groups(&slave->dev, slave_groups);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_device_add_group(&slave->dev, &sdw_slave_dev_attr_group);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (slave->prop.dp0_prop) {
|
||||
ret = devm_device_add_group(&slave->dev, &dp0_group);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (slave->prop.source_ports || slave->prop.sink_ports) {
|
||||
ret = sdw_slave_sysfs_dpn_init(slave);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
300
drivers/soundwire/sysfs_slave_dpn.c
Normal file
300
drivers/soundwire/sysfs_slave_dpn.c
Normal file
@ -0,0 +1,300 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright(c) 2015-2020 Intel Corporation.
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include "bus.h"
|
||||
#include "sysfs_local.h"
|
||||
|
||||
struct dpn_attribute {
|
||||
struct device_attribute dev_attr;
|
||||
int N;
|
||||
int dir;
|
||||
const char *format_string;
|
||||
};
|
||||
|
||||
/*
|
||||
* Since we can't use ARRAY_SIZE, hard-code number of dpN attributes.
|
||||
* This needs to be updated when adding new attributes - an error will be
|
||||
* flagged on a mismatch.
|
||||
*/
|
||||
#define SDW_DPN_ATTRIBUTES 15
|
||||
|
||||
#define sdw_dpn_attribute_alloc(field) \
|
||||
static int field##_attribute_alloc(struct device *dev, \
|
||||
struct attribute **res, \
|
||||
int N, int dir, \
|
||||
const char *format_string) \
|
||||
{ \
|
||||
struct dpn_attribute *dpn_attr; \
|
||||
\
|
||||
dpn_attr = devm_kzalloc(dev, sizeof(*dpn_attr), GFP_KERNEL); \
|
||||
if (!dpn_attr) \
|
||||
return -ENOMEM; \
|
||||
dpn_attr->N = N; \
|
||||
dpn_attr->dir = dir; \
|
||||
dpn_attr->format_string = format_string; \
|
||||
dpn_attr->dev_attr.attr.name = __stringify(field); \
|
||||
dpn_attr->dev_attr.attr.mode = 0444; \
|
||||
dpn_attr->dev_attr.show = field##_show; \
|
||||
\
|
||||
*res = &dpn_attr->dev_attr.attr; \
|
||||
\
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define sdw_dpn_attr(field) \
|
||||
\
|
||||
static ssize_t field##_dpn_show(struct sdw_slave *slave, \
|
||||
int N, \
|
||||
int dir, \
|
||||
const char *format_string, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct sdw_dpn_prop *dpn; \
|
||||
unsigned long mask; \
|
||||
int bit; \
|
||||
int i; \
|
||||
\
|
||||
if (dir) { \
|
||||
dpn = slave->prop.src_dpn_prop; \
|
||||
mask = slave->prop.source_ports; \
|
||||
} else { \
|
||||
dpn = slave->prop.sink_dpn_prop; \
|
||||
mask = slave->prop.sink_ports; \
|
||||
} \
|
||||
\
|
||||
i = 0; \
|
||||
for_each_set_bit(bit, &mask, 32) { \
|
||||
if (bit == N) { \
|
||||
return sprintf(buf, format_string, \
|
||||
dpn[i].field); \
|
||||
} \
|
||||
i++; \
|
||||
} \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
\
|
||||
static ssize_t field##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct sdw_slave *slave = dev_to_sdw_dev(dev); \
|
||||
struct dpn_attribute *dpn_attr = \
|
||||
container_of(attr, struct dpn_attribute, dev_attr); \
|
||||
\
|
||||
return field##_dpn_show(slave, \
|
||||
dpn_attr->N, dpn_attr->dir, \
|
||||
dpn_attr->format_string, \
|
||||
buf); \
|
||||
} \
|
||||
sdw_dpn_attribute_alloc(field)
|
||||
|
||||
sdw_dpn_attr(imp_def_interrupts);
|
||||
sdw_dpn_attr(max_word);
|
||||
sdw_dpn_attr(min_word);
|
||||
sdw_dpn_attr(type);
|
||||
sdw_dpn_attr(max_grouping);
|
||||
sdw_dpn_attr(simple_ch_prep_sm);
|
||||
sdw_dpn_attr(ch_prep_timeout);
|
||||
sdw_dpn_attr(max_ch);
|
||||
sdw_dpn_attr(min_ch);
|
||||
sdw_dpn_attr(max_async_buffer);
|
||||
sdw_dpn_attr(block_pack_mode);
|
||||
sdw_dpn_attr(port_encoding);
|
||||
|
||||
#define sdw_dpn_array_attr(field) \
|
||||
\
|
||||
static ssize_t field##_dpn_show(struct sdw_slave *slave, \
|
||||
int N, \
|
||||
int dir, \
|
||||
const char *format_string, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct sdw_dpn_prop *dpn; \
|
||||
unsigned long mask; \
|
||||
ssize_t size = 0; \
|
||||
int bit; \
|
||||
int i; \
|
||||
int j; \
|
||||
\
|
||||
if (dir) { \
|
||||
dpn = slave->prop.src_dpn_prop; \
|
||||
mask = slave->prop.source_ports; \
|
||||
} else { \
|
||||
dpn = slave->prop.sink_dpn_prop; \
|
||||
mask = slave->prop.sink_ports; \
|
||||
} \
|
||||
\
|
||||
i = 0; \
|
||||
for_each_set_bit(bit, &mask, 32) { \
|
||||
if (bit == N) { \
|
||||
for (j = 0; j < dpn[i].num_##field; j++) \
|
||||
size += sprintf(buf + size, \
|
||||
format_string, \
|
||||
dpn[i].field[j]); \
|
||||
size += sprintf(buf + size, "\n"); \
|
||||
return size; \
|
||||
} \
|
||||
i++; \
|
||||
} \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
static ssize_t field##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct sdw_slave *slave = dev_to_sdw_dev(dev); \
|
||||
struct dpn_attribute *dpn_attr = \
|
||||
container_of(attr, struct dpn_attribute, dev_attr); \
|
||||
\
|
||||
return field##_dpn_show(slave, \
|
||||
dpn_attr->N, dpn_attr->dir, \
|
||||
dpn_attr->format_string, \
|
||||
buf); \
|
||||
} \
|
||||
sdw_dpn_attribute_alloc(field)
|
||||
|
||||
sdw_dpn_array_attr(words);
|
||||
sdw_dpn_array_attr(ch_combinations);
|
||||
sdw_dpn_array_attr(channels);
|
||||
|
||||
static int add_all_attributes(struct device *dev, int N, int dir)
|
||||
{
|
||||
struct attribute **dpn_attrs;
|
||||
struct attribute_group *dpn_group;
|
||||
int i = 0;
|
||||
int ret;
|
||||
|
||||
/* allocate attributes, last one is NULL */
|
||||
dpn_attrs = devm_kcalloc(dev, SDW_DPN_ATTRIBUTES + 1,
|
||||
sizeof(struct attribute *),
|
||||
GFP_KERNEL);
|
||||
if (!dpn_attrs)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = max_word_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = min_word_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = words_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = type_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = max_grouping_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = simple_ch_prep_sm_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ch_prep_timeout_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = imp_def_interrupts_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "0x%x\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = min_ch_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = max_ch_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = channels_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ch_combinations_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = max_async_buffer_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = block_pack_mode_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = port_encoding_attribute_alloc(dev, &dpn_attrs[i++],
|
||||
N, dir, "%d\n");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* paranoia check for editing mistakes */
|
||||
if (i != SDW_DPN_ATTRIBUTES) {
|
||||
dev_err(dev, "mismatch in attributes, allocated %d got %d\n",
|
||||
SDW_DPN_ATTRIBUTES, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dpn_group = devm_kzalloc(dev, sizeof(*dpn_group), GFP_KERNEL);
|
||||
if (!dpn_group)
|
||||
return -ENOMEM;
|
||||
|
||||
dpn_group->attrs = dpn_attrs;
|
||||
dpn_group->name = devm_kasprintf(dev, GFP_KERNEL, "dp%d_%s",
|
||||
N, dir ? "src" : "sink");
|
||||
if (!dpn_group->name)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_device_add_group(dev, dpn_group);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave)
|
||||
{
|
||||
unsigned long mask;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
mask = slave->prop.source_ports;
|
||||
for_each_set_bit(i, &mask, 32) {
|
||||
ret = add_all_attributes(&slave->dev, i, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
mask = slave->prop.sink_ports;
|
||||
for_each_set_bit(i, &mask, 32) {
|
||||
ret = add_all_attributes(&slave->dev, i, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -291,8 +291,8 @@ struct sdw_dpn_audio_mode {
|
||||
* implementation-defined interrupts
|
||||
* @max_ch: Maximum channels supported
|
||||
* @min_ch: Minimum channels supported
|
||||
* @num_ch: Number of discrete channels supported
|
||||
* @ch: Discrete channels supported
|
||||
* @num_channels: Number of discrete channels supported
|
||||
* @channels: Discrete channels supported
|
||||
* @num_ch_combinations: Number of channel combinations supported
|
||||
* @ch_combinations: Channel combinations supported
|
||||
* @modes: SDW mode supported
|
||||
@ -316,8 +316,8 @@ struct sdw_dpn_prop {
|
||||
u32 imp_def_interrupts;
|
||||
u32 max_ch;
|
||||
u32 min_ch;
|
||||
u32 num_ch;
|
||||
u32 *ch;
|
||||
u32 num_channels;
|
||||
u32 *channels;
|
||||
u32 num_ch_combinations;
|
||||
u32 *ch_combinations;
|
||||
u32 modes;
|
||||
@ -632,6 +632,19 @@ struct sdw_slave {
|
||||
|
||||
#define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev)
|
||||
|
||||
/**
|
||||
* struct sdw_master_device - SoundWire 'Master Device' representation
|
||||
* @dev: Linux device for this Master
|
||||
* @bus: Bus handle shortcut
|
||||
*/
|
||||
struct sdw_master_device {
|
||||
struct device dev;
|
||||
struct sdw_bus *bus;
|
||||
};
|
||||
|
||||
#define dev_to_sdw_master_device(d) \
|
||||
container_of(d, struct sdw_master_device, dev)
|
||||
|
||||
struct sdw_driver {
|
||||
const char *name;
|
||||
|
||||
@ -787,8 +800,10 @@ struct sdw_master_ops {
|
||||
|
||||
/**
|
||||
* struct sdw_bus - SoundWire bus
|
||||
* @dev: Master linux device
|
||||
* @dev: Shortcut to &bus->md->dev to avoid changing the entire code.
|
||||
* @md: Master device
|
||||
* @link_id: Link id number, can be 0 to N, unique for each Master
|
||||
* @id: bus system-wide unique id
|
||||
* @slaves: list of Slaves on this bus
|
||||
* @assigned: Bitmap for Slave device numbers.
|
||||
* Bit set implies used number, bit clear implies unused number.
|
||||
@ -812,7 +827,9 @@ struct sdw_master_ops {
|
||||
*/
|
||||
struct sdw_bus {
|
||||
struct device *dev;
|
||||
struct sdw_master_device *md;
|
||||
unsigned int link_id;
|
||||
int id;
|
||||
struct list_head slaves;
|
||||
DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
|
||||
struct mutex bus_lock;
|
||||
@ -832,8 +849,9 @@ struct sdw_bus {
|
||||
bool multi_link;
|
||||
};
|
||||
|
||||
int sdw_add_bus_master(struct sdw_bus *bus);
|
||||
void sdw_delete_bus_master(struct sdw_bus *bus);
|
||||
int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
|
||||
struct fwnode_handle *fwnode);
|
||||
void sdw_bus_master_delete(struct sdw_bus *bus);
|
||||
|
||||
/**
|
||||
* sdw_port_config: Master or Slave Port configuration
|
||||
|
@ -5,6 +5,13 @@
|
||||
#define __SOUNDWIRE_TYPES_H
|
||||
|
||||
extern struct bus_type sdw_bus_type;
|
||||
extern struct device_type sdw_slave_type;
|
||||
extern struct device_type sdw_master_type;
|
||||
|
||||
static inline int is_sdw_slave(const struct device *dev)
|
||||
{
|
||||
return dev->type == &sdw_slave_type;
|
||||
}
|
||||
|
||||
#define drv_to_sdw_driver(_drv) container_of(_drv, struct sdw_driver, driver)
|
||||
|
||||
@ -14,7 +21,7 @@ extern struct bus_type sdw_bus_type;
|
||||
int __sdw_register_driver(struct sdw_driver *drv, struct module *owner);
|
||||
void sdw_unregister_driver(struct sdw_driver *drv);
|
||||
|
||||
int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size);
|
||||
int sdw_slave_uevent(struct device *dev, struct kobj_uevent_env *env);
|
||||
|
||||
/**
|
||||
* module_sdw_driver() - Helper macro for registering a Soundwire driver
|
||||
|
Loading…
x
Reference in New Issue
Block a user