Merge branch 'topic/firewire' into for-next
Pull FireWire fixes Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Коммит
bea11f0aa1
|
@ -16,6 +16,7 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- mediatek,mt8186-mt6366-rt1019-rt5682s-sound
|
||||
- mediatek,mt8186-mt6366-rt5682s-max98360-sound
|
||||
|
||||
mediatek,platform:
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle"
|
||||
|
|
|
@ -30,7 +30,9 @@ properties:
|
|||
const: 0
|
||||
|
||||
clocks:
|
||||
maxItems: 5
|
||||
oneOf:
|
||||
- maxItems: 3
|
||||
- maxItems: 5
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
|
|
|
@ -9,9 +9,6 @@ title: LPASS(Low Power Audio Subsystem) VA Macro audio codec
|
|||
maintainers:
|
||||
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
|
@ -30,15 +27,12 @@ properties:
|
|||
const: 0
|
||||
|
||||
clocks:
|
||||
maxItems: 5
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: mclk
|
||||
- const: npl
|
||||
- const: macro
|
||||
- const: dcodec
|
||||
- const: fsgen
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
@ -55,10 +49,51 @@ required:
|
|||
- reg
|
||||
- "#sound-dai-cells"
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sc7280-lpass-wsa-macro
|
||||
- qcom,sm8450-lpass-wsa-macro
|
||||
- qcom,sc8280xp-lpass-wsa-macro
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 5
|
||||
clock-names:
|
||||
items:
|
||||
- const: mclk
|
||||
- const: npl
|
||||
- const: macro
|
||||
- const: dcodec
|
||||
- const: fsgen
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sm8250-lpass-wsa-macro
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 6
|
||||
clock-names:
|
||||
items:
|
||||
- const: mclk
|
||||
- const: npl
|
||||
- const: macro
|
||||
- const: dcodec
|
||||
- const: va
|
||||
- const: fsgen
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,sm8250-lpass-aoncc.h>
|
||||
#include <dt-bindings/sound/qcom,q6afe.h>
|
||||
codec@3240000 {
|
||||
compatible = "qcom,sm8250-lpass-wsa-macro";
|
||||
|
@ -69,7 +104,8 @@ examples:
|
|||
<&audiocc 0>,
|
||||
<&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
|
||||
<&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
|
||||
<&aoncc LPASS_CDC_VA_MCLK>,
|
||||
<&vamacro>;
|
||||
clock-names = "mclk", "npl", "macro", "dcodec", "fsgen";
|
||||
clock-names = "mclk", "npl", "macro", "dcodec", "va", "fsgen";
|
||||
clock-output-names = "mclk";
|
||||
};
|
||||
|
|
|
@ -111,6 +111,7 @@ struct inbound_transaction_resource {
|
|||
struct client_resource resource;
|
||||
struct fw_card *card;
|
||||
struct fw_request *request;
|
||||
bool is_fcp;
|
||||
void *data;
|
||||
size_t length;
|
||||
};
|
||||
|
@ -643,19 +644,14 @@ static int ioctl_send_request(struct client *client, union ioctl_arg *arg)
|
|||
client->device->max_speed);
|
||||
}
|
||||
|
||||
static inline bool is_fcp_request(struct fw_request *request)
|
||||
{
|
||||
return request == NULL;
|
||||
}
|
||||
|
||||
static void release_request(struct client *client,
|
||||
struct client_resource *resource)
|
||||
{
|
||||
struct inbound_transaction_resource *r = container_of(resource,
|
||||
struct inbound_transaction_resource, resource);
|
||||
|
||||
if (is_fcp_request(r->request))
|
||||
kfree(r->data);
|
||||
if (r->is_fcp)
|
||||
fw_request_put(r->request);
|
||||
else
|
||||
fw_send_response(r->card, r->request, RCODE_CONFLICT_ERROR);
|
||||
|
||||
|
@ -669,15 +665,20 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
|
|||
void *payload, size_t length, void *callback_data)
|
||||
{
|
||||
struct address_handler_resource *handler = callback_data;
|
||||
bool is_fcp = is_in_fcp_region(offset, length);
|
||||
struct inbound_transaction_resource *r;
|
||||
struct inbound_transaction_event *e;
|
||||
size_t event_size0;
|
||||
void *fcp_frame = NULL;
|
||||
int ret;
|
||||
|
||||
/* card may be different from handler->client->device->card */
|
||||
fw_card_get(card);
|
||||
|
||||
// Extend the lifetime of data for request so that its payload is safely accessible in
|
||||
// the process context for the client.
|
||||
if (is_fcp)
|
||||
fw_request_get(request);
|
||||
|
||||
r = kmalloc(sizeof(*r), GFP_ATOMIC);
|
||||
e = kmalloc(sizeof(*e), GFP_ATOMIC);
|
||||
if (r == NULL || e == NULL)
|
||||
|
@ -685,21 +686,10 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
|
|||
|
||||
r->card = card;
|
||||
r->request = request;
|
||||
r->is_fcp = is_fcp;
|
||||
r->data = payload;
|
||||
r->length = length;
|
||||
|
||||
if (is_fcp_request(request)) {
|
||||
/*
|
||||
* FIXME: Let core-transaction.c manage a
|
||||
* single reference-counted copy?
|
||||
*/
|
||||
fcp_frame = kmemdup(payload, length, GFP_ATOMIC);
|
||||
if (fcp_frame == NULL)
|
||||
goto failed;
|
||||
|
||||
r->data = fcp_frame;
|
||||
}
|
||||
|
||||
r->resource.release = release_request;
|
||||
ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC);
|
||||
if (ret < 0)
|
||||
|
@ -741,10 +731,11 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
|
|||
failed:
|
||||
kfree(r);
|
||||
kfree(e);
|
||||
kfree(fcp_frame);
|
||||
|
||||
if (!is_fcp_request(request))
|
||||
if (!is_fcp)
|
||||
fw_send_response(card, request, RCODE_CONFLICT_ERROR);
|
||||
else
|
||||
fw_request_put(request);
|
||||
|
||||
fw_card_put(card);
|
||||
}
|
||||
|
@ -819,17 +810,19 @@ static int ioctl_send_response(struct client *client, union ioctl_arg *arg)
|
|||
|
||||
r = container_of(resource, struct inbound_transaction_resource,
|
||||
resource);
|
||||
if (is_fcp_request(r->request))
|
||||
if (r->is_fcp) {
|
||||
fw_request_put(r->request);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (a->length != fw_get_response_length(r->request)) {
|
||||
ret = -EINVAL;
|
||||
kfree(r->request);
|
||||
fw_request_put(r->request);
|
||||
goto out;
|
||||
}
|
||||
if (copy_from_user(r->data, u64_to_uptr(a->data), a->length)) {
|
||||
ret = -EFAULT;
|
||||
kfree(r->request);
|
||||
fw_request_put(r->request);
|
||||
goto out;
|
||||
}
|
||||
fw_send_response(r->card, r->request, a->rcode);
|
||||
|
|
|
@ -535,12 +535,6 @@ const struct fw_address_region fw_unit_space_region =
|
|||
{ .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, };
|
||||
#endif /* 0 */
|
||||
|
||||
static bool is_in_fcp_region(u64 offset, size_t length)
|
||||
{
|
||||
return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
|
||||
offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END);
|
||||
}
|
||||
|
||||
/**
|
||||
* fw_core_add_address_handler() - register for incoming requests
|
||||
* @handler: callback
|
||||
|
@ -617,6 +611,7 @@ void fw_core_remove_address_handler(struct fw_address_handler *handler)
|
|||
EXPORT_SYMBOL(fw_core_remove_address_handler);
|
||||
|
||||
struct fw_request {
|
||||
struct kref kref;
|
||||
struct fw_packet response;
|
||||
u32 request_header[4];
|
||||
int ack;
|
||||
|
@ -625,13 +620,33 @@ struct fw_request {
|
|||
u32 data[];
|
||||
};
|
||||
|
||||
void fw_request_get(struct fw_request *request)
|
||||
{
|
||||
kref_get(&request->kref);
|
||||
}
|
||||
|
||||
static void release_request(struct kref *kref)
|
||||
{
|
||||
struct fw_request *request = container_of(kref, struct fw_request, kref);
|
||||
|
||||
kfree(request);
|
||||
}
|
||||
|
||||
void fw_request_put(struct fw_request *request)
|
||||
{
|
||||
kref_put(&request->kref, release_request);
|
||||
}
|
||||
|
||||
static void free_response_callback(struct fw_packet *packet,
|
||||
struct fw_card *card, int status)
|
||||
{
|
||||
struct fw_request *request;
|
||||
struct fw_request *request = container_of(packet, struct fw_request, response);
|
||||
|
||||
request = container_of(packet, struct fw_request, response);
|
||||
kfree(request);
|
||||
// Decrease the reference count since not at in-flight.
|
||||
fw_request_put(request);
|
||||
|
||||
// Decrease the reference count to release the object.
|
||||
fw_request_put(request);
|
||||
}
|
||||
|
||||
int fw_get_response_length(struct fw_request *r)
|
||||
|
@ -782,6 +797,7 @@ static struct fw_request *allocate_request(struct fw_card *card,
|
|||
request = kmalloc(sizeof(*request) + length, GFP_ATOMIC);
|
||||
if (request == NULL)
|
||||
return NULL;
|
||||
kref_init(&request->kref);
|
||||
|
||||
request->response.speed = p->speed;
|
||||
request->response.timestamp =
|
||||
|
@ -800,16 +816,22 @@ static struct fw_request *allocate_request(struct fw_card *card,
|
|||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* fw_send_response: - send response packet for asynchronous transaction.
|
||||
* @card: interface to send the response at.
|
||||
* @request: firewire request data for the transaction.
|
||||
* @rcode: response code to send.
|
||||
*
|
||||
* Submit a response packet into the asynchronous response transmission queue. The @request
|
||||
* is going to be released when the transmission successfully finishes later.
|
||||
*/
|
||||
void fw_send_response(struct fw_card *card,
|
||||
struct fw_request *request, int rcode)
|
||||
{
|
||||
if (WARN_ONCE(!request, "invalid for FCP address handlers"))
|
||||
return;
|
||||
|
||||
/* unified transaction or broadcast transaction: don't respond */
|
||||
if (request->ack != ACK_PENDING ||
|
||||
HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) {
|
||||
kfree(request);
|
||||
fw_request_put(request);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -821,6 +843,9 @@ void fw_send_response(struct fw_card *card,
|
|||
fw_fill_response(&request->response, request->request_header,
|
||||
rcode, NULL, 0);
|
||||
|
||||
// Increase the reference count so that the object is kept during in-flight.
|
||||
fw_request_get(request);
|
||||
|
||||
card->driver->send_response(card, &request->response);
|
||||
}
|
||||
EXPORT_SYMBOL(fw_send_response);
|
||||
|
@ -910,7 +935,7 @@ static void handle_fcp_region_request(struct fw_card *card,
|
|||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(handler, &address_handler_list, link) {
|
||||
if (is_enclosing_handler(handler, offset, request->length))
|
||||
handler->address_callback(card, NULL, tcode,
|
||||
handler->address_callback(card, request, tcode,
|
||||
destination, source,
|
||||
p->generation, offset,
|
||||
request->data,
|
||||
|
|
|
@ -244,6 +244,9 @@ int fw_get_response_length(struct fw_request *request);
|
|||
void fw_fill_response(struct fw_packet *response, u32 *request_header,
|
||||
int rcode, void *payload, size_t length);
|
||||
|
||||
void fw_request_get(struct fw_request *request);
|
||||
void fw_request_put(struct fw_request *request);
|
||||
|
||||
#define FW_PHY_CONFIG_NO_NODE_ID -1
|
||||
#define FW_PHY_CONFIG_CURRENT_GAP_COUNT -1
|
||||
void fw_send_phy_config(struct fw_card *card,
|
||||
|
@ -254,4 +257,10 @@ static inline bool is_ping_packet(u32 *data)
|
|||
return (data[0] & 0xc0ffffff) == 0 && ~data[0] == data[1];
|
||||
}
|
||||
|
||||
static inline bool is_in_fcp_region(u64 offset, size_t length)
|
||||
{
|
||||
return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
|
||||
offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END);
|
||||
}
|
||||
|
||||
#endif /* _FIREWIRE_CORE_H */
|
||||
|
|
|
@ -1253,6 +1253,11 @@ static int mtk_spi_probe(struct platform_device *pdev)
|
|||
dev_notice(dev, "SPI dma_set_mask(%d) failed, ret:%d\n",
|
||||
addr_bits, ret);
|
||||
|
||||
ret = devm_request_irq(dev, irq, mtk_spi_interrupt,
|
||||
IRQF_TRIGGER_NONE, dev_name(dev), master);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to register irq\n");
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = devm_spi_register_master(dev, master);
|
||||
|
@ -1261,13 +1266,6 @@ static int mtk_spi_probe(struct platform_device *pdev)
|
|||
return dev_err_probe(dev, ret, "failed to register master\n");
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, irq, mtk_spi_interrupt,
|
||||
IRQF_TRIGGER_NONE, dev_name(dev), master);
|
||||
if (ret) {
|
||||
pm_runtime_disable(dev);
|
||||
return dev_err_probe(dev, ret, "failed to register irq\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -278,9 +278,8 @@ typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
|
|||
* Otherwise there is a danger of recursion of inbound and outbound
|
||||
* transactions from and to the local node.
|
||||
*
|
||||
* The callback is responsible that either fw_send_response() or kfree()
|
||||
* is called on the @request, except for FCP registers for which the core
|
||||
* takes care of that.
|
||||
* The callback is responsible that fw_send_response() is called on the @request, except for FCP
|
||||
* registers for which the core takes care of that.
|
||||
*/
|
||||
typedef void (*fw_address_callback_t)(struct fw_card *card,
|
||||
struct fw_request *request,
|
||||
|
|
|
@ -1203,14 +1203,19 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
|||
const u32 pattern = 0xdeadbeef;
|
||||
int ret;
|
||||
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, &control->id);
|
||||
if (kctl == NULL)
|
||||
return -ENOENT;
|
||||
if (kctl == NULL) {
|
||||
ret = -ENOENT;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
index_offset = snd_ctl_get_ioff(kctl, &control->id);
|
||||
vd = &kctl->vd[index_offset];
|
||||
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL)
|
||||
return -EPERM;
|
||||
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) {
|
||||
ret = -EPERM;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
snd_ctl_build_ioff(&control->id, kctl, index_offset);
|
||||
|
||||
|
@ -1220,7 +1225,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
|||
info.id = control->id;
|
||||
ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto unlock;
|
||||
#endif
|
||||
|
||||
if (!snd_ctl_skip_validation(&info))
|
||||
|
@ -1230,7 +1235,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
|||
ret = kctl->get(kctl, control);
|
||||
snd_power_unref(card);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto unlock;
|
||||
if (!snd_ctl_skip_validation(&info) &&
|
||||
sanity_check_elem_value(card, control, &info, pattern) < 0) {
|
||||
dev_err(card->dev,
|
||||
|
@ -1238,8 +1243,11 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
|||
control->id.iface, control->id.device,
|
||||
control->id.subdevice, control->id.name,
|
||||
control->id.index);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
unlock:
|
||||
up_read(&card->controls_rwsem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1253,9 +1261,7 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
|
|||
if (IS_ERR(control))
|
||||
return PTR_ERR(control);
|
||||
|
||||
down_read(&card->controls_rwsem);
|
||||
result = snd_ctl_elem_read(card, control);
|
||||
up_read(&card->controls_rwsem);
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
|
|
|
@ -530,12 +530,11 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si
|
|||
bool attach)
|
||||
{
|
||||
char buf2[256], *s, *os;
|
||||
size_t len = max(sizeof(s) - 1, count);
|
||||
struct snd_ctl_elem_id id;
|
||||
int err;
|
||||
|
||||
strncpy(buf2, buf, len);
|
||||
buf2[len] = '\0';
|
||||
if (strscpy(buf2, buf, sizeof(buf2)) < 0)
|
||||
return -E2BIG;
|
||||
memset(&id, 0, sizeof(id));
|
||||
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
s = buf2;
|
||||
|
|
|
@ -598,8 +598,8 @@ static int cs35l41_system_suspend(struct device *dev)
|
|||
dev_dbg(cs35l41->dev, "System Suspend\n");
|
||||
|
||||
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
|
||||
dev_err(cs35l41->dev, "System Suspend not supported\n");
|
||||
return -EINVAL;
|
||||
dev_err_once(cs35l41->dev, "System Suspend not supported\n");
|
||||
return 0; /* don't block the whole system suspend */
|
||||
}
|
||||
|
||||
ret = pm_runtime_force_suspend(dev);
|
||||
|
@ -624,8 +624,8 @@ static int cs35l41_system_resume(struct device *dev)
|
|||
dev_dbg(cs35l41->dev, "System Resume\n");
|
||||
|
||||
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
|
||||
dev_err(cs35l41->dev, "System Resume not supported\n");
|
||||
return -EINVAL;
|
||||
dev_err_once(cs35l41->dev, "System Resume not supported\n");
|
||||
return 0; /* don't block the whole system resume */
|
||||
}
|
||||
|
||||
if (cs35l41->reset_gpio) {
|
||||
|
@ -647,6 +647,15 @@ static int cs35l41_system_resume(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int cs35l41_runtime_idle(struct device *dev)
|
||||
{
|
||||
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
|
||||
|
||||
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH)
|
||||
return -EBUSY; /* suspend not supported yet on this model */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs35l41_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
|
||||
|
@ -1536,7 +1545,8 @@ void cs35l41_hda_remove(struct device *dev)
|
|||
EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41);
|
||||
|
||||
const struct dev_pm_ops cs35l41_hda_pm_ops = {
|
||||
RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, NULL)
|
||||
RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume,
|
||||
cs35l41_runtime_idle)
|
||||
SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume)
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41);
|
||||
|
|
|
@ -144,6 +144,7 @@ static int hda_codec_driver_probe(struct device *dev)
|
|||
|
||||
error:
|
||||
snd_hda_codec_cleanup_for_unbind(codec);
|
||||
codec->preset = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -166,6 +167,7 @@ static int hda_codec_driver_remove(struct device *dev)
|
|||
if (codec->patch_ops.free)
|
||||
codec->patch_ops.free(codec);
|
||||
snd_hda_codec_cleanup_for_unbind(codec);
|
||||
codec->preset = NULL;
|
||||
module_put(dev->driver->owner);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -795,7 +795,6 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
|
|||
snd_array_free(&codec->cvt_setups);
|
||||
snd_array_free(&codec->spdif_out);
|
||||
snd_array_free(&codec->verbs);
|
||||
codec->preset = NULL;
|
||||
codec->follower_dig_outs = NULL;
|
||||
codec->spdif_status_reset = 0;
|
||||
snd_array_free(&codec->mixers);
|
||||
|
|
|
@ -1981,6 +1981,7 @@ static const struct snd_pci_quirk force_connect_list[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1),
|
||||
SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1),
|
||||
SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1),
|
||||
SND_PCI_QUIRK(0x103c, 0x8715, "HP", 1),
|
||||
SND_PCI_QUIRK(0x1462, 0xec94, "MS-7C94", 1),
|
||||
SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", 1),
|
||||
{}
|
||||
|
|
|
@ -3564,6 +3564,15 @@ static void alc256_init(struct hda_codec *codec)
|
|||
hda_nid_t hp_pin = alc_get_hp_pin(spec);
|
||||
bool hp_pin_sense;
|
||||
|
||||
if (spec->ultra_low_power) {
|
||||
alc_update_coef_idx(codec, 0x03, 1<<1, 1<<1);
|
||||
alc_update_coef_idx(codec, 0x08, 3<<2, 3<<2);
|
||||
alc_update_coef_idx(codec, 0x08, 7<<4, 0);
|
||||
alc_update_coef_idx(codec, 0x3b, 1<<15, 0);
|
||||
alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
|
||||
msleep(30);
|
||||
}
|
||||
|
||||
if (!hp_pin)
|
||||
hp_pin = 0x21;
|
||||
|
||||
|
@ -3575,14 +3584,6 @@ static void alc256_init(struct hda_codec *codec)
|
|||
msleep(2);
|
||||
|
||||
alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
|
||||
if (spec->ultra_low_power) {
|
||||
alc_update_coef_idx(codec, 0x03, 1<<1, 1<<1);
|
||||
alc_update_coef_idx(codec, 0x08, 3<<2, 3<<2);
|
||||
alc_update_coef_idx(codec, 0x08, 7<<4, 0);
|
||||
alc_update_coef_idx(codec, 0x3b, 1<<15, 0);
|
||||
alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
|
||||
msleep(30);
|
||||
}
|
||||
|
||||
snd_hda_codec_write(codec, hp_pin, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
|
||||
|
@ -3713,6 +3714,13 @@ static void alc225_init(struct hda_codec *codec)
|
|||
hda_nid_t hp_pin = alc_get_hp_pin(spec);
|
||||
bool hp1_pin_sense, hp2_pin_sense;
|
||||
|
||||
if (spec->ultra_low_power) {
|
||||
alc_update_coef_idx(codec, 0x08, 0x0f << 2, 3<<2);
|
||||
alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
|
||||
alc_update_coef_idx(codec, 0x33, 1<<11, 0);
|
||||
msleep(30);
|
||||
}
|
||||
|
||||
if (spec->codec_variant != ALC269_TYPE_ALC287 &&
|
||||
spec->codec_variant != ALC269_TYPE_ALC245)
|
||||
/* required only at boot or S3 and S4 resume time */
|
||||
|
@ -3734,12 +3742,6 @@ static void alc225_init(struct hda_codec *codec)
|
|||
msleep(2);
|
||||
|
||||
alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
|
||||
if (spec->ultra_low_power) {
|
||||
alc_update_coef_idx(codec, 0x08, 0x0f << 2, 3<<2);
|
||||
alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
|
||||
alc_update_coef_idx(codec, 0x33, 1<<11, 0);
|
||||
msleep(30);
|
||||
}
|
||||
|
||||
if (hp1_pin_sense || spec->ultra_low_power)
|
||||
snd_hda_codec_write(codec, hp_pin, 0,
|
||||
|
@ -4644,6 +4646,16 @@ static void alc285_fixup_hp_coef_micmute_led(struct hda_codec *codec,
|
|||
}
|
||||
}
|
||||
|
||||
static void alc285_fixup_hp_gpio_micmute_led(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
if (action == HDA_FIXUP_ACT_PRE_PROBE)
|
||||
spec->micmute_led_polarity = 1;
|
||||
alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
|
||||
}
|
||||
|
||||
static void alc236_fixup_hp_coef_micmute_led(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
|
@ -4665,6 +4677,13 @@ static void alc285_fixup_hp_mute_led(struct hda_codec *codec,
|
|||
alc285_fixup_hp_coef_micmute_led(codec, fix, action);
|
||||
}
|
||||
|
||||
static void alc285_fixup_hp_spectre_x360_mute_led(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
|
||||
alc285_fixup_hp_gpio_micmute_led(codec, fix, action);
|
||||
}
|
||||
|
||||
static void alc236_fixup_hp_mute_led(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
|
@ -7106,6 +7125,7 @@ enum {
|
|||
ALC285_FIXUP_ASUS_G533Z_PINS,
|
||||
ALC285_FIXUP_HP_GPIO_LED,
|
||||
ALC285_FIXUP_HP_MUTE_LED,
|
||||
ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED,
|
||||
ALC236_FIXUP_HP_GPIO_LED,
|
||||
ALC236_FIXUP_HP_MUTE_LED,
|
||||
ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF,
|
||||
|
@ -8486,6 +8506,10 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc285_fixup_hp_mute_led,
|
||||
},
|
||||
[ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc285_fixup_hp_spectre_x360_mute_led,
|
||||
},
|
||||
[ALC236_FIXUP_HP_GPIO_LED] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc236_fixup_hp_gpio_led,
|
||||
|
@ -9239,6 +9263,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1028, 0x0b1a, "Dell Precision 5570", ALC289_FIXUP_DUAL_SPK),
|
||||
SND_PCI_QUIRK(0x1028, 0x0b37, "Dell Inspiron 16 Plus 7620 2-in-1", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
|
||||
SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
|
||||
SND_PCI_QUIRK(0x1028, 0x0c03, "Dell Precision 5340", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
|
||||
SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
|
||||
SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
|
||||
|
@ -9327,6 +9352,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
|
||||
SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
|
||||
SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
|
||||
SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8720, "HP EliteBook x360 1040 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED),
|
||||
|
@ -9406,6 +9432,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
|
||||
SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
|
||||
SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
|
||||
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
|
|
|
@ -819,6 +819,9 @@ static int add_secret_dac_path(struct hda_codec *codec)
|
|||
return 0;
|
||||
nums = snd_hda_get_connections(codec, spec->gen.mixer_nid, conn,
|
||||
ARRAY_SIZE(conn) - 1);
|
||||
if (nums < 0)
|
||||
return nums;
|
||||
|
||||
for (i = 0; i < nums; i++) {
|
||||
if (get_wcaps_type(get_wcaps(codec, conn[i])) == AC_WID_AUD_OUT)
|
||||
return 0;
|
||||
|
|
|
@ -206,6 +206,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
|
|||
DMI_MATCH(DMI_PRODUCT_NAME, "UM5302TA"),
|
||||
}
|
||||
},
|
||||
{
|
||||
.driver_data = &acp6x_card,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "M5402RA"),
|
||||
}
|
||||
},
|
||||
{
|
||||
.driver_data = &acp6x_card,
|
||||
.matches = {
|
||||
|
@ -220,6 +227,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
|
|||
DMI_MATCH(DMI_PRODUCT_NAME, "Redmi Book Pro 14 2022"),
|
||||
}
|
||||
},
|
||||
{
|
||||
.driver_data = &acp6x_card,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Razer"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Blade 14 (2022) - RZ09-0427"),
|
||||
}
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
@ -177,8 +177,20 @@ static int rt9120_codec_probe(struct snd_soc_component *comp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rt9120_codec_suspend(struct snd_soc_component *comp)
|
||||
{
|
||||
return pm_runtime_force_suspend(comp->dev);
|
||||
}
|
||||
|
||||
static int rt9120_codec_resume(struct snd_soc_component *comp)
|
||||
{
|
||||
return pm_runtime_force_resume(comp->dev);
|
||||
}
|
||||
|
||||
static const struct snd_soc_component_driver rt9120_component_driver = {
|
||||
.probe = rt9120_codec_probe,
|
||||
.suspend = rt9120_codec_suspend,
|
||||
.resume = rt9120_codec_resume,
|
||||
.controls = rt9120_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(rt9120_snd_controls),
|
||||
.dapm_widgets = rt9120_dapm_widgets,
|
||||
|
|
|
@ -697,6 +697,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
|
|||
int dcs_mask;
|
||||
int dcs_l, dcs_r;
|
||||
int dcs_l_reg, dcs_r_reg;
|
||||
int an_out_reg;
|
||||
int timeout;
|
||||
int pwr_reg;
|
||||
|
||||
|
@ -712,6 +713,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
|
|||
dcs_mask = WM8904_DCS_ENA_CHAN_0 | WM8904_DCS_ENA_CHAN_1;
|
||||
dcs_r_reg = WM8904_DC_SERVO_8;
|
||||
dcs_l_reg = WM8904_DC_SERVO_9;
|
||||
an_out_reg = WM8904_ANALOGUE_OUT1_LEFT;
|
||||
dcs_l = 0;
|
||||
dcs_r = 1;
|
||||
break;
|
||||
|
@ -720,6 +722,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
|
|||
dcs_mask = WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_3;
|
||||
dcs_r_reg = WM8904_DC_SERVO_6;
|
||||
dcs_l_reg = WM8904_DC_SERVO_7;
|
||||
an_out_reg = WM8904_ANALOGUE_OUT2_LEFT;
|
||||
dcs_l = 2;
|
||||
dcs_r = 3;
|
||||
break;
|
||||
|
@ -792,6 +795,10 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
|
|||
snd_soc_component_update_bits(component, reg,
|
||||
WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
|
||||
WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP);
|
||||
|
||||
/* Update volume, requires PGA to be powered */
|
||||
val = snd_soc_component_read(component, an_out_reg);
|
||||
snd_soc_component_write(component, an_out_reg, val);
|
||||
break;
|
||||
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
|
|
|
@ -121,11 +121,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
|
|||
|
||||
static const struct snd_soc_dapm_route audio_map_ac97[] = {
|
||||
/* 1st half -- Normal DAPM routes */
|
||||
{"Playback", NULL, "AC97 Playback"},
|
||||
{"AC97 Capture", NULL, "Capture"},
|
||||
{"AC97 Playback", NULL, "CPU AC97 Playback"},
|
||||
{"CPU AC97 Capture", NULL, "AC97 Capture"},
|
||||
/* 2nd half -- ASRC DAPM routes */
|
||||
{"AC97 Playback", NULL, "ASRC-Playback"},
|
||||
{"ASRC-Capture", NULL, "AC97 Capture"},
|
||||
{"CPU AC97 Playback", NULL, "ASRC-Playback"},
|
||||
{"ASRC-Capture", NULL, "CPU AC97 Capture"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_map_tx[] = {
|
||||
|
|
|
@ -315,21 +315,21 @@ static int hwvad_detected(struct snd_kcontrol *kcontrol,
|
|||
|
||||
static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
|
||||
SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL,
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0x7, gain_tlv),
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(0), 0x8, 0xF, gain_tlv),
|
||||
SOC_SINGLE_SX_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL,
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0x7, gain_tlv),
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(1), 0x8, 0xF, gain_tlv),
|
||||
SOC_SINGLE_SX_TLV("CH2 Volume", REG_MICFIL_OUT_CTRL,
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0x7, gain_tlv),
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(2), 0x8, 0xF, gain_tlv),
|
||||
SOC_SINGLE_SX_TLV("CH3 Volume", REG_MICFIL_OUT_CTRL,
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0x7, gain_tlv),
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(3), 0x8, 0xF, gain_tlv),
|
||||
SOC_SINGLE_SX_TLV("CH4 Volume", REG_MICFIL_OUT_CTRL,
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0x7, gain_tlv),
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(4), 0x8, 0xF, gain_tlv),
|
||||
SOC_SINGLE_SX_TLV("CH5 Volume", REG_MICFIL_OUT_CTRL,
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0x7, gain_tlv),
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(5), 0x8, 0xF, gain_tlv),
|
||||
SOC_SINGLE_SX_TLV("CH6 Volume", REG_MICFIL_OUT_CTRL,
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0x7, gain_tlv),
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(6), 0x8, 0xF, gain_tlv),
|
||||
SOC_SINGLE_SX_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL,
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0x7, gain_tlv),
|
||||
MICFIL_OUTGAIN_CHX_SHIFT(7), 0x8, 0xF, gain_tlv),
|
||||
SOC_ENUM_EXT("MICFIL Quality Select",
|
||||
fsl_micfil_quality_enum,
|
||||
micfil_quality_get, micfil_quality_set),
|
||||
|
|
|
@ -1189,14 +1189,14 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
|
|||
.symmetric_channels = 1,
|
||||
.probe = fsl_ssi_dai_probe,
|
||||
.playback = {
|
||||
.stream_name = "AC97 Playback",
|
||||
.stream_name = "CPU AC97 Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S20,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "AC97 Capture",
|
||||
.stream_name = "CPU AC97 Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
|
|
|
@ -554,10 +554,12 @@ config SND_SOC_INTEL_SOF_NAU8825_MACH
|
|||
select SND_SOC_RT1015P
|
||||
select SND_SOC_MAX98373_I2C
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_NAU8315
|
||||
select SND_SOC_DMIC
|
||||
select SND_SOC_HDAC_HDMI
|
||||
select SND_SOC_INTEL_HDA_DSP_COMMON
|
||||
select SND_SOC_INTEL_SOF_MAXIM_COMMON
|
||||
select SND_SOC_INTEL_SOF_REALTEK_COMMON
|
||||
help
|
||||
This adds support for ASoC machine driver for SOF platforms
|
||||
with nau8825 codec.
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(15)
|
||||
#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(16)
|
||||
#define SOF_RT1015P_SPEAKER_AMP_PRESENT BIT(17)
|
||||
#define SOF_NAU8318_SPEAKER_AMP_PRESENT BIT(18)
|
||||
|
||||
static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0);
|
||||
|
||||
|
@ -338,6 +339,13 @@ static struct snd_soc_dai_link_component rt1019p_component[] = {
|
|||
}
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link_component nau8318_components[] = {
|
||||
{
|
||||
.name = "NVTN2012:00",
|
||||
.dai_name = "nau8315-hifi",
|
||||
}
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link_component dummy_component[] = {
|
||||
{
|
||||
.name = "snd-soc-dummy",
|
||||
|
@ -486,6 +494,11 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
|
|||
max_98360a_dai_link(&links[id]);
|
||||
} else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) {
|
||||
sof_rt1015p_dai_link(&links[id]);
|
||||
} else if (sof_nau8825_quirk &
|
||||
SOF_NAU8318_SPEAKER_AMP_PRESENT) {
|
||||
links[id].codecs = nau8318_components;
|
||||
links[id].num_codecs = ARRAY_SIZE(nau8318_components);
|
||||
links[id].init = speaker_codec_init;
|
||||
} else {
|
||||
goto devm_err;
|
||||
}
|
||||
|
@ -618,7 +631,7 @@ static const struct platform_device_id board_ids[] = {
|
|||
|
||||
},
|
||||
{
|
||||
.name = "adl_rt1019p_nau8825",
|
||||
.name = "adl_rt1019p_8825",
|
||||
.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
|
||||
SOF_SPEAKER_AMP_PRESENT |
|
||||
SOF_RT1019P_SPEAKER_AMP_PRESENT |
|
||||
|
@ -626,7 +639,7 @@ static const struct platform_device_id board_ids[] = {
|
|||
SOF_NAU8825_NUM_HDMIDEV(4)),
|
||||
},
|
||||
{
|
||||
.name = "adl_max98373_nau8825",
|
||||
.name = "adl_max98373_8825",
|
||||
.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
|
||||
SOF_SPEAKER_AMP_PRESENT |
|
||||
SOF_MAX98373_SPEAKER_AMP_PRESENT |
|
||||
|
@ -637,7 +650,7 @@ static const struct platform_device_id board_ids[] = {
|
|||
},
|
||||
{
|
||||
/* The limitation of length of char array, shorten the name */
|
||||
.name = "adl_mx98360a_nau8825",
|
||||
.name = "adl_mx98360a_8825",
|
||||
.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
|
||||
SOF_SPEAKER_AMP_PRESENT |
|
||||
SOF_MAX98360A_SPEAKER_AMP_PRESENT |
|
||||
|
@ -648,7 +661,7 @@ static const struct platform_device_id board_ids[] = {
|
|||
|
||||
},
|
||||
{
|
||||
.name = "adl_rt1015p_nau8825",
|
||||
.name = "adl_rt1015p_8825",
|
||||
.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
|
||||
SOF_SPEAKER_AMP_PRESENT |
|
||||
SOF_RT1015P_SPEAKER_AMP_PRESENT |
|
||||
|
@ -657,6 +670,16 @@ static const struct platform_device_id board_ids[] = {
|
|||
SOF_BT_OFFLOAD_SSP(2) |
|
||||
SOF_SSP_BT_OFFLOAD_PRESENT),
|
||||
},
|
||||
{
|
||||
.name = "adl_nau8318_8825",
|
||||
.driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
|
||||
SOF_SPEAKER_AMP_PRESENT |
|
||||
SOF_NAU8318_SPEAKER_AMP_PRESENT |
|
||||
SOF_NAU8825_SSP_AMP(1) |
|
||||
SOF_NAU8825_NUM_HDMIDEV(4) |
|
||||
SOF_BT_OFFLOAD_SSP(2) |
|
||||
SOF_SSP_BT_OFFLOAD_PRESENT),
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, board_ids);
|
||||
|
|
|
@ -450,6 +450,11 @@ static const struct snd_soc_acpi_codecs adl_lt6911_hdmi = {
|
|||
.codecs = {"INTC10B0"}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_codecs adl_nau8318_amp = {
|
||||
.num_codecs = 1,
|
||||
.codecs = {"NVTN2012"}
|
||||
};
|
||||
|
||||
struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
|
||||
{
|
||||
.comp_ids = &adl_rt5682_rt5682s_hp,
|
||||
|
@ -474,21 +479,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
|
|||
},
|
||||
{
|
||||
.id = "10508825",
|
||||
.drv_name = "adl_rt1019p_nau8825",
|
||||
.drv_name = "adl_rt1019p_8825",
|
||||
.machine_quirk = snd_soc_acpi_codec_list,
|
||||
.quirk_data = &adl_rt1019p_amp,
|
||||
.sof_tplg_filename = "sof-adl-rt1019-nau8825.tplg",
|
||||
},
|
||||
{
|
||||
.id = "10508825",
|
||||
.drv_name = "adl_max98373_nau8825",
|
||||
.drv_name = "adl_max98373_8825",
|
||||
.machine_quirk = snd_soc_acpi_codec_list,
|
||||
.quirk_data = &adl_max98373_amp,
|
||||
.sof_tplg_filename = "sof-adl-max98373-nau8825.tplg",
|
||||
},
|
||||
{
|
||||
.id = "10508825",
|
||||
.drv_name = "adl_mx98360a_nau8825",
|
||||
.drv_name = "adl_mx98360a_8825",
|
||||
.machine_quirk = snd_soc_acpi_codec_list,
|
||||
.quirk_data = &adl_max98360a_amp,
|
||||
.sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg",
|
||||
|
@ -502,11 +507,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
|
|||
},
|
||||
{
|
||||
.id = "10508825",
|
||||
.drv_name = "adl_rt1015p_nau8825",
|
||||
.drv_name = "adl_rt1015p_8825",
|
||||
.machine_quirk = snd_soc_acpi_codec_list,
|
||||
.quirk_data = &adl_rt1015p_amp,
|
||||
.sof_tplg_filename = "sof-adl-rt1015-nau8825.tplg",
|
||||
},
|
||||
{
|
||||
.id = "10508825",
|
||||
.drv_name = "adl_nau8318_8825",
|
||||
.machine_quirk = snd_soc_acpi_codec_list,
|
||||
.quirk_data = &adl_nau8318_amp,
|
||||
.sof_tplg_filename = "sof-adl-nau8318-nau8825.tplg",
|
||||
},
|
||||
{
|
||||
.id = "10508825",
|
||||
.drv_name = "sof_nau8825",
|
||||
|
|
|
@ -203,6 +203,25 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link2_rt1316_link01_rt71
|
|||
{}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link2_rt1316_link01[] = {
|
||||
{
|
||||
.mask = BIT(2),
|
||||
.num_adr = ARRAY_SIZE(rt711_sdca_2_adr),
|
||||
.adr_d = rt711_sdca_2_adr,
|
||||
},
|
||||
{
|
||||
.mask = BIT(0),
|
||||
.num_adr = ARRAY_SIZE(rt1316_0_group2_adr),
|
||||
.adr_d = rt1316_0_group2_adr,
|
||||
},
|
||||
{
|
||||
.mask = BIT(1),
|
||||
.num_adr = ARRAY_SIZE(rt1316_1_group2_adr),
|
||||
.adr_d = rt1316_1_group2_adr,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12_rt714_link3[] = {
|
||||
{
|
||||
.mask = BIT(0),
|
||||
|
@ -227,6 +246,25 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12_rt71
|
|||
{}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12[] = {
|
||||
{
|
||||
.mask = BIT(0),
|
||||
.num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
|
||||
.adr_d = rt711_sdca_0_adr,
|
||||
},
|
||||
{
|
||||
.mask = BIT(1),
|
||||
.num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
|
||||
.adr_d = rt1318_1_group1_adr,
|
||||
},
|
||||
{
|
||||
.mask = BIT(2),
|
||||
.num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
|
||||
.adr_d = rt1318_2_group1_adr,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] = {
|
||||
{
|
||||
.mask = BIT(1),
|
||||
|
@ -271,12 +309,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = {
|
|||
.drv_name = "sof_sdw",
|
||||
.sof_tplg_filename = "sof-rpl-rt711-l0-rt1318-l12-rt714-l3.tplg",
|
||||
},
|
||||
{
|
||||
.link_mask = 0x7, /* rt711 on link0 & two rt1318s on link1 and link2 */
|
||||
.links = rpl_sdw_rt711_link0_rt1318_link12,
|
||||
.drv_name = "sof_sdw",
|
||||
.sof_tplg_filename = "sof-rpl-rt711-l0-rt1318-l12.tplg",
|
||||
},
|
||||
{
|
||||
.link_mask = 0x7, /* rt714 on link0 & two rt1316s on link1 and link2 */
|
||||
.links = rpl_sdw_rt1316_link12_rt714_link0,
|
||||
.drv_name = "sof_sdw",
|
||||
.sof_tplg_filename = "sof-rpl-rt1316-l12-rt714-l0.tplg",
|
||||
},
|
||||
{
|
||||
.link_mask = 0x7, /* rt711 on link2 & two rt1316s on link0 and link1 */
|
||||
.links = rpl_sdw_rt711_link2_rt1316_link01,
|
||||
.drv_name = "sof_sdw",
|
||||
.sof_tplg_filename = "sof-rpl-rt711-l2-rt1316-l01.tplg",
|
||||
},
|
||||
{
|
||||
.link_mask = 0x1, /* link0 required */
|
||||
.links = rpl_rvp,
|
||||
|
|
|
@ -182,10 +182,12 @@ config SND_SOC_MT8186_MT6366_DA7219_MAX98357
|
|||
If unsure select "N".
|
||||
|
||||
config SND_SOC_MT8186_MT6366_RT1019_RT5682S
|
||||
tristate "ASoC Audio driver for MT8186 with RT1019 RT5682S codec"
|
||||
tristate "ASoC Audio driver for MT8186 with RT1019 RT5682S MAX98357A/MAX98360 codec"
|
||||
depends on I2C && GPIOLIB
|
||||
depends on SND_SOC_MT8186 && MTK_PMIC_WRAP
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_MT6358
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_RT1015P
|
||||
select SND_SOC_RT5682S
|
||||
select SND_SOC_BT_SCO
|
||||
|
|
|
@ -1083,6 +1083,21 @@ static struct snd_soc_card mt8186_mt6366_rt1019_rt5682s_soc_card = {
|
|||
.num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf),
|
||||
};
|
||||
|
||||
static struct snd_soc_card mt8186_mt6366_rt5682s_max98360_soc_card = {
|
||||
.name = "mt8186_rt5682s_max98360",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = mt8186_mt6366_rt1019_rt5682s_dai_links,
|
||||
.num_links = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links),
|
||||
.controls = mt8186_mt6366_rt1019_rt5682s_controls,
|
||||
.num_controls = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_controls),
|
||||
.dapm_widgets = mt8186_mt6366_rt1019_rt5682s_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_widgets),
|
||||
.dapm_routes = mt8186_mt6366_rt1019_rt5682s_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_routes),
|
||||
.codec_conf = mt8186_mt6366_rt1019_rt5682s_codec_conf,
|
||||
.num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf),
|
||||
};
|
||||
|
||||
static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card;
|
||||
|
@ -1232,9 +1247,14 @@ err_adsp_node:
|
|||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static const struct of_device_id mt8186_mt6366_rt1019_rt5682s_dt_match[] = {
|
||||
{ .compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound",
|
||||
{
|
||||
.compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound",
|
||||
.data = &mt8186_mt6366_rt1019_rt5682s_soc_card,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8186-mt6366-rt5682s-max98360-sound",
|
||||
.data = &mt8186_mt6366_rt5682s_max98360_soc_card,
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mt8186_mt6366_rt1019_rt5682s_dt_match);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
menuconfig SND_SOC_QCOM
|
||||
tristate "ASoC support for QCOM platforms"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
imply SND_SOC_QCOM_COMMON
|
||||
help
|
||||
Say Y or M if you want to add support to use audio devices
|
||||
in Qualcomm Technologies SOC-based platforms.
|
||||
|
@ -60,14 +59,16 @@ config SND_SOC_STORM
|
|||
config SND_SOC_APQ8016_SBC
|
||||
tristate "SoC Audio support for APQ8016 SBC platforms"
|
||||
select SND_SOC_LPASS_APQ8016
|
||||
depends on SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_QCOM_COMMON
|
||||
help
|
||||
Support for Qualcomm Technologies LPASS audio block in
|
||||
APQ8016 SOC-based systems.
|
||||
Say Y if you want to use audio devices on MI2S.
|
||||
|
||||
config SND_SOC_QCOM_COMMON
|
||||
depends on SOUNDWIRE
|
||||
tristate
|
||||
|
||||
config SND_SOC_QCOM_SDW
|
||||
tristate
|
||||
|
||||
config SND_SOC_QDSP6_COMMON
|
||||
|
@ -144,7 +145,7 @@ config SND_SOC_MSM8996
|
|||
depends on QCOM_APR
|
||||
depends on COMMON_CLK
|
||||
select SND_SOC_QDSP6
|
||||
depends on SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_QCOM_COMMON
|
||||
help
|
||||
Support for Qualcomm Technologies LPASS audio block in
|
||||
APQ8096 SoC-based systems.
|
||||
|
@ -155,7 +156,7 @@ config SND_SOC_SDM845
|
|||
depends on QCOM_APR && I2C && SOUNDWIRE
|
||||
depends on COMMON_CLK
|
||||
select SND_SOC_QDSP6
|
||||
depends on SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_RT5663
|
||||
select SND_SOC_MAX98927
|
||||
imply SND_SOC_CROS_EC_CODEC
|
||||
|
@ -169,7 +170,8 @@ config SND_SOC_SM8250
|
|||
depends on QCOM_APR && SOUNDWIRE
|
||||
depends on COMMON_CLK
|
||||
select SND_SOC_QDSP6
|
||||
depends on SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_QCOM_SDW
|
||||
help
|
||||
To add support for audio on Qualcomm Technologies Inc.
|
||||
SM8250 SoC-based systems.
|
||||
|
@ -180,7 +182,8 @@ config SND_SOC_SC8280XP
|
|||
depends on QCOM_APR && SOUNDWIRE
|
||||
depends on COMMON_CLK
|
||||
select SND_SOC_QDSP6
|
||||
depends on SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_QCOM_SDW
|
||||
help
|
||||
To add support for audio on Qualcomm Technologies Inc.
|
||||
SC8280XP SoC-based systems.
|
||||
|
@ -190,7 +193,7 @@ config SND_SOC_SC7180
|
|||
tristate "SoC Machine driver for SC7180 boards"
|
||||
depends on I2C && GPIOLIB
|
||||
depends on SOUNDWIRE || SOUNDWIRE=n
|
||||
depends on SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_LPASS_SC7180
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_RT5682_I2C
|
||||
|
@ -204,7 +207,7 @@ config SND_SOC_SC7180
|
|||
config SND_SOC_SC7280
|
||||
tristate "SoC Machine driver for SC7280 boards"
|
||||
depends on I2C && SOUNDWIRE
|
||||
depends on SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_LPASS_SC7280
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_WCD938X_SDW
|
||||
|
|
|
@ -28,6 +28,7 @@ snd-soc-sdm845-objs := sdm845.o
|
|||
snd-soc-sm8250-objs := sm8250.o
|
||||
snd-soc-sc8280xp-objs := sc8280xp.o
|
||||
snd-soc-qcom-common-objs := common.o
|
||||
snd-soc-qcom-sdw-objs := sdw.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
|
||||
obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
|
||||
|
@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_SC8280XP) += snd-soc-sc8280xp.o
|
|||
obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
|
||||
obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o
|
||||
obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
|
||||
obj-$(CONFIG_SND_SOC_QCOM_SDW) += snd-soc-qcom-sdw.o
|
||||
|
||||
#DSP lib
|
||||
obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/
|
||||
|
|
|
@ -180,120 +180,6 @@ err_put_np:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_snd_parse_of);
|
||||
|
||||
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *sruntime,
|
||||
bool *stream_prepared)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||
int ret;
|
||||
|
||||
if (!sruntime)
|
||||
return 0;
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case WSA_CODEC_DMA_RX_0:
|
||||
case WSA_CODEC_DMA_RX_1:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case RX_CODEC_DMA_RX_1:
|
||||
case TX_CODEC_DMA_TX_0:
|
||||
case TX_CODEC_DMA_TX_1:
|
||||
case TX_CODEC_DMA_TX_2:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*stream_prepared) {
|
||||
sdw_disable_stream(sruntime);
|
||||
sdw_deprepare_stream(sruntime);
|
||||
*stream_prepared = false;
|
||||
}
|
||||
|
||||
ret = sdw_prepare_stream(sruntime);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/**
|
||||
* NOTE: there is a strict hw requirement about the ordering of port
|
||||
* enables and actual WSA881x PA enable. PA enable should only happen
|
||||
* after soundwire ports are enabled if not DC on the line is
|
||||
* accumulated resulting in Click/Pop Noise
|
||||
* PA enable/mute are handled as part of codec DAPM and digital mute.
|
||||
*/
|
||||
|
||||
ret = sdw_enable_stream(sruntime);
|
||||
if (ret) {
|
||||
sdw_deprepare_stream(sruntime);
|
||||
return ret;
|
||||
}
|
||||
*stream_prepared = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
|
||||
|
||||
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct sdw_stream_runtime **psruntime)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||
struct sdw_stream_runtime *sruntime;
|
||||
int i;
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case WSA_CODEC_DMA_RX_0:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case RX_CODEC_DMA_RX_1:
|
||||
case TX_CODEC_DMA_TX_0:
|
||||
case TX_CODEC_DMA_TX_1:
|
||||
case TX_CODEC_DMA_TX_2:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai) {
|
||||
sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
|
||||
if (sruntime != ERR_PTR(-ENOTSUPP))
|
||||
*psruntime = sruntime;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
|
||||
|
||||
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *sruntime, bool *stream_prepared)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case WSA_CODEC_DMA_RX_0:
|
||||
case WSA_CODEC_DMA_RX_1:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case RX_CODEC_DMA_RX_1:
|
||||
case TX_CODEC_DMA_TX_0:
|
||||
case TX_CODEC_DMA_TX_1:
|
||||
case TX_CODEC_DMA_TX_2:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
if (sruntime && *stream_prepared) {
|
||||
sdw_disable_stream(sruntime);
|
||||
sdw_deprepare_stream(sruntime);
|
||||
*stream_prepared = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
|
||||
|
||||
int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_soc_jack *jack, bool *jack_setup)
|
||||
{
|
||||
|
|
|
@ -5,19 +5,9 @@
|
|||
#define __QCOM_SND_COMMON_H__
|
||||
|
||||
#include <sound/soc.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
|
||||
int qcom_snd_parse_of(struct snd_soc_card *card);
|
||||
int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_soc_jack *jack, bool *jack_setup);
|
||||
|
||||
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *runtime,
|
||||
bool *stream_prepared);
|
||||
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct sdw_stream_runtime **psruntime);
|
||||
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *sruntime,
|
||||
bool *stream_prepared);
|
||||
#endif
|
||||
|
|
|
@ -1037,10 +1037,11 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
|
|||
struct lpass_data *data)
|
||||
{
|
||||
struct device_node *node;
|
||||
int ret, id;
|
||||
int ret, i, id;
|
||||
|
||||
/* Allow all channels by default for backwards compatibility */
|
||||
for (id = 0; id < data->variant->num_dai; id++) {
|
||||
for (i = 0; i < data->variant->num_dai; i++) {
|
||||
id = data->variant->dai_driver[i].id;
|
||||
data->mi2s_playback_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
|
||||
data->mi2s_capture_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/input-event-codes.h>
|
||||
#include "qdsp6/q6afe.h"
|
||||
#include "common.h"
|
||||
#include "sdw.h"
|
||||
|
||||
#define DRIVER_NAME "sc8280xp"
|
||||
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018, Linaro Limited.
|
||||
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
#include "qdsp6/q6afe.h"
|
||||
#include "sdw.h"
|
||||
|
||||
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *sruntime,
|
||||
bool *stream_prepared)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||
int ret;
|
||||
|
||||
if (!sruntime)
|
||||
return 0;
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case WSA_CODEC_DMA_RX_0:
|
||||
case WSA_CODEC_DMA_RX_1:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case RX_CODEC_DMA_RX_1:
|
||||
case TX_CODEC_DMA_TX_0:
|
||||
case TX_CODEC_DMA_TX_1:
|
||||
case TX_CODEC_DMA_TX_2:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*stream_prepared) {
|
||||
sdw_disable_stream(sruntime);
|
||||
sdw_deprepare_stream(sruntime);
|
||||
*stream_prepared = false;
|
||||
}
|
||||
|
||||
ret = sdw_prepare_stream(sruntime);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/**
|
||||
* NOTE: there is a strict hw requirement about the ordering of port
|
||||
* enables and actual WSA881x PA enable. PA enable should only happen
|
||||
* after soundwire ports are enabled if not DC on the line is
|
||||
* accumulated resulting in Click/Pop Noise
|
||||
* PA enable/mute are handled as part of codec DAPM and digital mute.
|
||||
*/
|
||||
|
||||
ret = sdw_enable_stream(sruntime);
|
||||
if (ret) {
|
||||
sdw_deprepare_stream(sruntime);
|
||||
return ret;
|
||||
}
|
||||
*stream_prepared = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
|
||||
|
||||
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct sdw_stream_runtime **psruntime)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||
struct sdw_stream_runtime *sruntime;
|
||||
int i;
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case WSA_CODEC_DMA_RX_0:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case RX_CODEC_DMA_RX_1:
|
||||
case TX_CODEC_DMA_TX_0:
|
||||
case TX_CODEC_DMA_TX_1:
|
||||
case TX_CODEC_DMA_TX_2:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai) {
|
||||
sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
|
||||
if (sruntime != ERR_PTR(-ENOTSUPP))
|
||||
*psruntime = sruntime;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
|
||||
|
||||
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *sruntime, bool *stream_prepared)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case WSA_CODEC_DMA_RX_0:
|
||||
case WSA_CODEC_DMA_RX_1:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case RX_CODEC_DMA_RX_1:
|
||||
case TX_CODEC_DMA_TX_0:
|
||||
case TX_CODEC_DMA_TX_1:
|
||||
case TX_CODEC_DMA_TX_2:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
if (sruntime && *stream_prepared) {
|
||||
sdw_disable_stream(sruntime);
|
||||
sdw_deprepare_stream(sruntime);
|
||||
*stream_prepared = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,18 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
|
||||
#ifndef __QCOM_SND_SDW_H__
|
||||
#define __QCOM_SND_SDW_H__
|
||||
|
||||
#include <linux/soundwire/sdw.h>
|
||||
|
||||
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *runtime,
|
||||
bool *stream_prepared);
|
||||
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct sdw_stream_runtime **psruntime);
|
||||
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *sruntime,
|
||||
bool *stream_prepared);
|
||||
#endif
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/input-event-codes.h>
|
||||
#include "qdsp6/q6afe.h"
|
||||
#include "common.h"
|
||||
#include "sdw.h"
|
||||
|
||||
#define DRIVER_NAME "sm8250"
|
||||
#define MI2S_BCLK_RATE 1536000
|
||||
|
|
|
@ -353,7 +353,9 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return snd_sof_debugfs_buf_item(sdev, &sdev->fw_state,
|
||||
sizeof(sdev->fw_state),
|
||||
"fw_state", 0444);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_sof_dbg_init);
|
||||
|
||||
|
|
|
@ -182,7 +182,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
|
|||
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
|
||||
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
|
||||
pm_message_t pm_state;
|
||||
u32 target_state = 0;
|
||||
u32 target_state = snd_sof_dsp_power_target(sdev);
|
||||
int ret;
|
||||
|
||||
/* do nothing if dsp suspend callback is not set */
|
||||
|
@ -192,6 +192,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
|
|||
if (runtime_suspend && !sof_ops(sdev)->runtime_suspend)
|
||||
return 0;
|
||||
|
||||
if (tplg_ops && tplg_ops->tear_down_all_pipelines)
|
||||
tplg_ops->tear_down_all_pipelines(sdev, false);
|
||||
|
||||
if (sdev->fw_state != SOF_FW_BOOT_COMPLETE)
|
||||
goto suspend;
|
||||
|
||||
|
@ -206,7 +209,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
|
|||
}
|
||||
}
|
||||
|
||||
target_state = snd_sof_dsp_power_target(sdev);
|
||||
pm_state.event = target_state;
|
||||
|
||||
/* Skip to platform-specific suspend if DSP is entering D0 */
|
||||
|
@ -217,9 +219,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
|
|||
goto suspend;
|
||||
}
|
||||
|
||||
if (tplg_ops->tear_down_all_pipelines)
|
||||
tplg_ops->tear_down_all_pipelines(sdev, false);
|
||||
|
||||
/* suspend DMA trace */
|
||||
sof_fw_trace_suspend(sdev, pm_state);
|
||||
|
||||
|
|
|
@ -471,7 +471,7 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip,
|
|||
subs = find_matching_substream(chip, stream, target->sync_ep,
|
||||
target->fmt_type);
|
||||
if (!subs)
|
||||
return sync_fmt;
|
||||
goto end;
|
||||
|
||||
high_score = 0;
|
||||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
||||
|
@ -485,6 +485,7 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip,
|
|||
}
|
||||
}
|
||||
|
||||
end:
|
||||
if (fixed_rate)
|
||||
*fixed_rate = snd_usb_pcm_has_fixed_rate(subs);
|
||||
return sync_fmt;
|
||||
|
|
222
sound/usb/pcm.c
222
sound/usb/pcm.c
|
@ -160,9 +160,12 @@ find_substream_format(struct snd_usb_substream *subs,
|
|||
bool snd_usb_pcm_has_fixed_rate(struct snd_usb_substream *subs)
|
||||
{
|
||||
const struct audioformat *fp;
|
||||
struct snd_usb_audio *chip = subs->stream->chip;
|
||||
struct snd_usb_audio *chip;
|
||||
int rate = -1;
|
||||
|
||||
if (!subs)
|
||||
return false;
|
||||
chip = subs->stream->chip;
|
||||
if (!(chip->quirk_flags & QUIRK_FLAG_FIXED_RATE))
|
||||
return false;
|
||||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
||||
|
@ -525,6 +528,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
|
|||
if (snd_usb_endpoint_compatible(chip, subs->data_endpoint,
|
||||
fmt, hw_params))
|
||||
goto unlock;
|
||||
if (stop_endpoints(subs, false))
|
||||
sync_pending_stops(subs);
|
||||
close_endpoints(chip, subs);
|
||||
}
|
||||
|
||||
|
@ -787,11 +792,27 @@ static int apply_hw_params_minmax(struct snd_interval *it, unsigned int rmin,
|
|||
return changed;
|
||||
}
|
||||
|
||||
/* get the specified endpoint object that is being used by other streams
|
||||
* (i.e. the parameter is locked)
|
||||
*/
|
||||
static const struct snd_usb_endpoint *
|
||||
get_endpoint_in_use(struct snd_usb_audio *chip, int endpoint,
|
||||
const struct snd_usb_endpoint *ref_ep)
|
||||
{
|
||||
const struct snd_usb_endpoint *ep;
|
||||
|
||||
ep = snd_usb_get_endpoint(chip, endpoint);
|
||||
if (ep && ep->cur_audiofmt && (ep != ref_ep || ep->opened > 1))
|
||||
return ep;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int hw_rule_rate(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct snd_usb_substream *subs = rule->private;
|
||||
struct snd_usb_audio *chip = subs->stream->chip;
|
||||
const struct snd_usb_endpoint *ep;
|
||||
const struct audioformat *fp;
|
||||
struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
||||
unsigned int rmin, rmax, r;
|
||||
|
@ -803,6 +824,29 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
|
|||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
||||
if (!hw_check_valid_format(subs, params, fp))
|
||||
continue;
|
||||
|
||||
ep = get_endpoint_in_use(chip, fp->endpoint,
|
||||
subs->data_endpoint);
|
||||
if (ep) {
|
||||
hwc_debug("rate limit %d for ep#%x\n",
|
||||
ep->cur_rate, fp->endpoint);
|
||||
rmin = min(rmin, ep->cur_rate);
|
||||
rmax = max(rmax, ep->cur_rate);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fp->implicit_fb) {
|
||||
ep = get_endpoint_in_use(chip, fp->sync_ep,
|
||||
subs->sync_endpoint);
|
||||
if (ep) {
|
||||
hwc_debug("rate limit %d for sync_ep#%x\n",
|
||||
ep->cur_rate, fp->sync_ep);
|
||||
rmin = min(rmin, ep->cur_rate);
|
||||
rmax = max(rmax, ep->cur_rate);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
r = snd_usb_endpoint_get_clock_rate(chip, fp->clock);
|
||||
if (r > 0) {
|
||||
if (!snd_interval_test(it, r))
|
||||
|
@ -872,6 +916,8 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
|
|||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct snd_usb_substream *subs = rule->private;
|
||||
struct snd_usb_audio *chip = subs->stream->chip;
|
||||
const struct snd_usb_endpoint *ep;
|
||||
const struct audioformat *fp;
|
||||
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
||||
u64 fbits;
|
||||
|
@ -881,6 +927,27 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
|
|||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
||||
if (!hw_check_valid_format(subs, params, fp))
|
||||
continue;
|
||||
|
||||
ep = get_endpoint_in_use(chip, fp->endpoint,
|
||||
subs->data_endpoint);
|
||||
if (ep) {
|
||||
hwc_debug("format limit %d for ep#%x\n",
|
||||
ep->cur_format, fp->endpoint);
|
||||
fbits |= pcm_format_to_bits(ep->cur_format);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fp->implicit_fb) {
|
||||
ep = get_endpoint_in_use(chip, fp->sync_ep,
|
||||
subs->sync_endpoint);
|
||||
if (ep) {
|
||||
hwc_debug("format limit %d for sync_ep#%x\n",
|
||||
ep->cur_format, fp->sync_ep);
|
||||
fbits |= pcm_format_to_bits(ep->cur_format);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fbits |= fp->formats;
|
||||
}
|
||||
return apply_hw_params_format_bits(fmt, fbits);
|
||||
|
@ -913,98 +980,95 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params,
|
|||
return apply_hw_params_minmax(it, pmin, UINT_MAX);
|
||||
}
|
||||
|
||||
/* get the EP or the sync EP for implicit fb when it's already set up */
|
||||
static const struct snd_usb_endpoint *
|
||||
get_sync_ep_from_substream(struct snd_usb_substream *subs)
|
||||
{
|
||||
struct snd_usb_audio *chip = subs->stream->chip;
|
||||
const struct audioformat *fp;
|
||||
const struct snd_usb_endpoint *ep;
|
||||
|
||||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
||||
ep = snd_usb_get_endpoint(chip, fp->endpoint);
|
||||
if (ep && ep->cur_audiofmt) {
|
||||
/* if EP is already opened solely for this substream,
|
||||
* we still allow us to change the parameter; otherwise
|
||||
* this substream has to follow the existing parameter
|
||||
*/
|
||||
if (ep->cur_audiofmt != subs->cur_audiofmt || ep->opened > 1)
|
||||
return ep;
|
||||
}
|
||||
if (!fp->implicit_fb)
|
||||
continue;
|
||||
/* for the implicit fb, check the sync ep as well */
|
||||
ep = snd_usb_get_endpoint(chip, fp->sync_ep);
|
||||
if (ep && ep->cur_audiofmt)
|
||||
return ep;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* additional hw constraints for implicit feedback mode */
|
||||
static int hw_rule_format_implicit_fb(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct snd_usb_substream *subs = rule->private;
|
||||
const struct snd_usb_endpoint *ep;
|
||||
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
||||
|
||||
ep = get_sync_ep_from_substream(subs);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
hwc_debug("applying %s\n", __func__);
|
||||
return apply_hw_params_format_bits(fmt, pcm_format_to_bits(ep->cur_format));
|
||||
}
|
||||
|
||||
static int hw_rule_rate_implicit_fb(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct snd_usb_substream *subs = rule->private;
|
||||
const struct snd_usb_endpoint *ep;
|
||||
struct snd_interval *it;
|
||||
|
||||
ep = get_sync_ep_from_substream(subs);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
hwc_debug("applying %s\n", __func__);
|
||||
it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
||||
return apply_hw_params_minmax(it, ep->cur_rate, ep->cur_rate);
|
||||
}
|
||||
|
||||
static int hw_rule_period_size_implicit_fb(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct snd_usb_substream *subs = rule->private;
|
||||
struct snd_usb_audio *chip = subs->stream->chip;
|
||||
const struct audioformat *fp;
|
||||
const struct snd_usb_endpoint *ep;
|
||||
struct snd_interval *it;
|
||||
unsigned int rmin, rmax;
|
||||
|
||||
ep = get_sync_ep_from_substream(subs);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
hwc_debug("applying %s\n", __func__);
|
||||
it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
|
||||
return apply_hw_params_minmax(it, ep->cur_period_frames,
|
||||
ep->cur_period_frames);
|
||||
hwc_debug("hw_rule_period_size: (%u,%u)\n", it->min, it->max);
|
||||
rmin = UINT_MAX;
|
||||
rmax = 0;
|
||||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
||||
if (!hw_check_valid_format(subs, params, fp))
|
||||
continue;
|
||||
ep = get_endpoint_in_use(chip, fp->endpoint,
|
||||
subs->data_endpoint);
|
||||
if (ep) {
|
||||
hwc_debug("period size limit %d for ep#%x\n",
|
||||
ep->cur_period_frames, fp->endpoint);
|
||||
rmin = min(rmin, ep->cur_period_frames);
|
||||
rmax = max(rmax, ep->cur_period_frames);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fp->implicit_fb) {
|
||||
ep = get_endpoint_in_use(chip, fp->sync_ep,
|
||||
subs->sync_endpoint);
|
||||
if (ep) {
|
||||
hwc_debug("period size limit %d for sync_ep#%x\n",
|
||||
ep->cur_period_frames, fp->sync_ep);
|
||||
rmin = min(rmin, ep->cur_period_frames);
|
||||
rmax = max(rmax, ep->cur_period_frames);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!rmax)
|
||||
return 0; /* no limit by implicit fb */
|
||||
return apply_hw_params_minmax(it, rmin, rmax);
|
||||
}
|
||||
|
||||
static int hw_rule_periods_implicit_fb(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct snd_usb_substream *subs = rule->private;
|
||||
struct snd_usb_audio *chip = subs->stream->chip;
|
||||
const struct audioformat *fp;
|
||||
const struct snd_usb_endpoint *ep;
|
||||
struct snd_interval *it;
|
||||
unsigned int rmin, rmax;
|
||||
|
||||
ep = get_sync_ep_from_substream(subs);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
hwc_debug("applying %s\n", __func__);
|
||||
it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
return apply_hw_params_minmax(it, ep->cur_buffer_periods,
|
||||
ep->cur_buffer_periods);
|
||||
hwc_debug("hw_rule_periods: (%u,%u)\n", it->min, it->max);
|
||||
rmin = UINT_MAX;
|
||||
rmax = 0;
|
||||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
||||
if (!hw_check_valid_format(subs, params, fp))
|
||||
continue;
|
||||
ep = get_endpoint_in_use(chip, fp->endpoint,
|
||||
subs->data_endpoint);
|
||||
if (ep) {
|
||||
hwc_debug("periods limit %d for ep#%x\n",
|
||||
ep->cur_buffer_periods, fp->endpoint);
|
||||
rmin = min(rmin, ep->cur_buffer_periods);
|
||||
rmax = max(rmax, ep->cur_buffer_periods);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fp->implicit_fb) {
|
||||
ep = get_endpoint_in_use(chip, fp->sync_ep,
|
||||
subs->sync_endpoint);
|
||||
if (ep) {
|
||||
hwc_debug("periods limit %d for sync_ep#%x\n",
|
||||
ep->cur_buffer_periods, fp->sync_ep);
|
||||
rmin = min(rmin, ep->cur_buffer_periods);
|
||||
rmax = max(rmax, ep->cur_buffer_periods);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!rmax)
|
||||
return 0; /* no limit by implicit fb */
|
||||
return apply_hw_params_minmax(it, rmin, rmax);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1113,16 +1177,6 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
|
|||
return err;
|
||||
|
||||
/* additional hw constraints for implicit fb */
|
||||
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
|
||||
hw_rule_format_implicit_fb, subs,
|
||||
SNDRV_PCM_HW_PARAM_FORMAT, -1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
hw_rule_rate_implicit_fb, subs,
|
||||
SNDRV_PCM_HW_PARAM_RATE, -1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
|
||||
hw_rule_period_size_implicit_fb, subs,
|
||||
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
|
||||
|
|
|
@ -2152,6 +2152,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
|
|||
QUIRK_FLAG_GENERIC_IMPLICIT_FB),
|
||||
DEVICE_FLG(0x0525, 0xa4ad, /* Hamedal C20 usb camero */
|
||||
QUIRK_FLAG_IFACE_SKIP_CLOSE),
|
||||
DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */
|
||||
QUIRK_FLAG_FIXED_RATE),
|
||||
DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */
|
||||
QUIRK_FLAG_FIXED_RATE),
|
||||
|
||||
|
|
|
@ -1222,6 +1222,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
|
|||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* try to set the interface... */
|
||||
usb_set_interface(chip->dev, iface_no, 0);
|
||||
snd_usb_init_pitch(chip, fp);
|
||||
snd_usb_init_sample_rate(chip, fp, fp->rate_max);
|
||||
usb_set_interface(chip->dev, iface_no, altno);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче