mirror of
https://github.com/torvalds/linux.git
synced 2026-09-29 12:24:02 +02:00
ASoC: Rework the SDCA HID code
Charles Keepax <ckeepax@opensource.cirrus.com> says: This series reworks the SDCA HID code, the primary goals being to no longer store runtime HID data in the DisCo data structures and remove the need to pass the soundwire device into the ACPI parsing code. To achieve this the HID device registration is moved to the IRQ work flow rather than the ACPI work flow. Also a few small issues are fixed up along the way, some formatting, some missing cleanup/docs. Link: https://patch.msgid.link/20260805124205.4152543-1-ckeepax@opensource.cirrus.com
This commit is contained in:
commit
476567107f
|
|
@ -107,9 +107,9 @@ int sdca_asoc_q78_put_volsw(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol);
|
||||
int sdca_asoc_q78_get_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap,
|
||||
int sdca_asoc_pde_poll_actual_ps(struct regmap *regmap,
|
||||
int function_id, int entity_id,
|
||||
int from_ps, int to_ps,
|
||||
const struct sdca_pde_delay *pde_delays,
|
||||
int num_delays);
|
||||
int from_ps, int to_ps,
|
||||
const struct sdca_pde_delay *pde_delays,
|
||||
int num_delays);
|
||||
#endif // __SDCA_ASOC_H__
|
||||
|
|
|
|||
|
|
@ -1116,7 +1116,6 @@ struct sdca_entity_ge {
|
|||
|
||||
/**
|
||||
* struct sdca_entity_hide - information specific to HIDE Entities
|
||||
* @hid: HID device structure
|
||||
* @num_hidtx_ids: number of HIDTx Report ID
|
||||
* @num_hidrx_ids: number of HIDRx Report ID
|
||||
* @hidtx_ids: HIDTx Report ID
|
||||
|
|
@ -1127,11 +1126,8 @@ struct sdca_entity_ge {
|
|||
* within this Device
|
||||
* @max_delay: the maximum time in microseconds allowed for the Device
|
||||
* to change the ownership from Device to Host
|
||||
* @hid_report_desc: HID Report Descriptor for the HIDE Entity
|
||||
* @hid_desc: HID descriptor for the HIDE Entity
|
||||
*/
|
||||
struct sdca_entity_hide {
|
||||
struct hid_device *hid;
|
||||
unsigned int *hidtx_ids;
|
||||
unsigned int *hidrx_ids;
|
||||
int num_hidtx_ids;
|
||||
|
|
@ -1139,8 +1135,6 @@ struct sdca_entity_hide {
|
|||
unsigned int af_number_list[SDCA_MAX_FUNCTION_COUNT];
|
||||
unsigned int hide_reside_function_num;
|
||||
unsigned int max_delay;
|
||||
unsigned char *hid_report_desc;
|
||||
struct hid_descriptor hid_desc;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1401,6 +1395,16 @@ struct sdca_fdl_data {
|
|||
int num_sets;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sdca_function_hid - information about a function's HID descriptors
|
||||
* @report_desc: HID Report Descriptor for the HID Function
|
||||
* @desc: HID descriptor for the HID Function
|
||||
*/
|
||||
struct sdca_function_hid {
|
||||
unsigned char *report_desc;
|
||||
struct hid_descriptor desc;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sdca_function_data - top-level information for one SDCA function
|
||||
* @desc: Pointer to short descriptor from initial parsing.
|
||||
|
|
@ -1415,6 +1419,7 @@ struct sdca_fdl_data {
|
|||
* @reset_max_delay: Maximum Function reset delay in microseconds, before an
|
||||
* error should be reported.
|
||||
* @fdl_data: FDL data for this Function, if available.
|
||||
* @hid: HID data for this Function, if available.
|
||||
*/
|
||||
struct sdca_function_data {
|
||||
struct sdca_function_desc *desc;
|
||||
|
|
@ -1430,6 +1435,10 @@ struct sdca_function_data {
|
|||
unsigned int reset_max_delay;
|
||||
|
||||
struct sdca_fdl_data fdl_data;
|
||||
|
||||
union {
|
||||
struct sdca_function_hid hid;
|
||||
};
|
||||
};
|
||||
|
||||
static inline u32 sdca_range(struct sdca_control_range *range,
|
||||
|
|
@ -1451,8 +1460,7 @@ static inline u32 sdca_range_search(struct sdca_control_range *range,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
|
||||
struct sdca_function_data *function);
|
||||
int sdca_parse_function(struct device *dev, struct sdca_function_data *function);
|
||||
|
||||
const char *sdca_find_terminal_name(enum sdca_terminal_type type);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,18 +16,21 @@ struct sdca_interrupt;
|
|||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SDCA_HID)
|
||||
|
||||
int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
|
||||
struct sdca_entity *entity);
|
||||
int sdca_add_hid_device(struct sdca_interrupt *interrupt);
|
||||
void sdca_destroy_hid_device(struct sdca_interrupt *interrupt);
|
||||
int sdca_hid_process_report(struct sdca_interrupt *interrupt);
|
||||
|
||||
#else
|
||||
|
||||
static inline int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
|
||||
struct sdca_entity *entity)
|
||||
static inline int sdca_add_hid_device(struct sdca_interrupt *interrupt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sdca_destroy_hid_device(struct sdca_interrupt *interrupt)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int sdca_hid_process_report(struct sdca_interrupt *interrupt)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <sound/sdca.h>
|
||||
#include <sound/sdca_asoc.h>
|
||||
#include <sound/sdca_function.h>
|
||||
#include <sound/sdca_hid.h>
|
||||
#include <sound/sdca_regmap.h>
|
||||
#include <sound/sdca_interrupts.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -33,7 +34,6 @@
|
|||
static int rt766_sdca_btn_detect(struct sdca_interrupt *interrupt)
|
||||
{
|
||||
struct rt766_sdca_priv *rt766 = interrupt->priv;
|
||||
struct sdca_entity *ent_hid = interrupt->entity;
|
||||
unsigned char *buf = NULL;
|
||||
unsigned int offset, owner, length;
|
||||
unsigned int det_mode, idx, val;
|
||||
|
|
@ -85,8 +85,8 @@ static int rt766_sdca_btn_detect(struct sdca_interrupt *interrupt)
|
|||
buf[idx] = val & 0xff;
|
||||
}
|
||||
|
||||
if (ent_hid)
|
||||
hid_input_report(ent_hid->hide.hid, HID_INPUT_REPORT,
|
||||
if (rt766->hid)
|
||||
hid_input_report(rt766->hid, HID_INPUT_REPORT,
|
||||
buf, length, 1);
|
||||
}
|
||||
|
||||
|
|
@ -191,6 +191,13 @@ static irqreturn_t rt766_sdca_irq_jd_handler(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void rt766_sdca_destroy_hid_device(struct sdca_interrupt *interrupt)
|
||||
{
|
||||
struct rt766_sdca_priv *rt766 = interrupt->priv;
|
||||
|
||||
hid_destroy_device(rt766->hid);
|
||||
}
|
||||
|
||||
static int rt766_sdca_irq_ctl(struct rt766_sdca_priv *rt766,
|
||||
struct sdca_function_data *function,
|
||||
struct snd_soc_component *component,
|
||||
|
|
@ -231,6 +238,15 @@ static int rt766_sdca_irq_ctl(struct rt766_sdca_priv *rt766,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (handler == rt766_sdca_irq_btn_handler) {
|
||||
ret = sdca_add_hid_device(interrupt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
interrupt->free_priv = rt766_sdca_destroy_hid_device;
|
||||
rt766->hid = interrupt->priv;
|
||||
}
|
||||
|
||||
interrupt->priv = rt766;
|
||||
ret = sdca_irq_request(dev, info, irq, interrupt->name,
|
||||
handler, interrupt);
|
||||
|
|
@ -616,7 +632,7 @@ static int rt766_sdca_pde_event(struct snd_soc_dapm_widget *w,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = sdca_asoc_pde_poll_actual_ps(component->dev, rt766->regmap,
|
||||
ret = sdca_asoc_pde_poll_actual_ps(rt766->regmap,
|
||||
func_num,
|
||||
pde_num,
|
||||
from_ps, to_ps,
|
||||
|
|
@ -1185,7 +1201,7 @@ int rt766_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave
|
|||
}
|
||||
|
||||
func_data_ptr->desc = &slave->sdca_data.function[i];
|
||||
ret = sdca_parse_function(dev, slave, func_data_ptr);
|
||||
ret = sdca_parse_function(dev, func_data_ptr);
|
||||
if (ret) {
|
||||
devm_kfree(dev, func_data_ptr);
|
||||
goto _free_dai_drv_;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#ifndef __RT766_H__
|
||||
#define __RT766_H__
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
|
|
@ -41,6 +42,7 @@ struct rt766_sdca_priv {
|
|||
struct sdca_function_data *sa_func_data;
|
||||
struct sdca_function_data *hid_func_data;
|
||||
struct sdca_interrupt_info *irq_info;
|
||||
struct hid_device *hid;
|
||||
};
|
||||
|
||||
/* vendor registers */
|
||||
|
|
|
|||
|
|
@ -800,7 +800,7 @@ static int tac_sdw_hw_params(struct snd_pcm_substream *substream,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, function_id, pde_entity,
|
||||
ret = sdca_asoc_pde_poll_actual_ps(tac_dev->regmap, function_id, pde_entity,
|
||||
SDCA_PDE_PS3, SDCA_PDE_PS0, NULL, 0);
|
||||
if (ret)
|
||||
dev_err(tac_dev->dev, "failed to transition func %d, pde %d from PS3 -> PS0, err=%d\n",
|
||||
|
|
@ -847,7 +847,7 @@ static int tac_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, function_id,
|
||||
ret = sdca_asoc_pde_poll_actual_ps(tac_dev->regmap, function_id,
|
||||
pde_entity, SDCA_PDE_PS0, SDCA_PDE_PS3,
|
||||
NULL, 0);
|
||||
if (ret)
|
||||
|
|
@ -1940,7 +1940,7 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral,
|
|||
"failed to allocate %s function data",
|
||||
func_name);
|
||||
function_data->desc = &peripheral->sdca_data.function[i];
|
||||
ret = sdca_parse_function(dev, peripheral, function_data);
|
||||
ret = sdca_parse_function(dev, function_data);
|
||||
if (!ret)
|
||||
*func_ptr = function_data;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1348,7 +1348,7 @@ static s32 tas_sdw_probe(struct sdw_slave *peripheral,
|
|||
function_data->desc = &peripheral->sdca_data.function[i];
|
||||
|
||||
/* Parse the function */
|
||||
ret = sdca_parse_function(dev, peripheral, function_data);
|
||||
ret = sdca_parse_function(dev, function_data);
|
||||
if (!ret)
|
||||
tas_dev->sa_func_data = function_data;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -364,7 +364,6 @@ static int entity_parse_ot(struct device *dev,
|
|||
|
||||
/**
|
||||
* sdca_asoc_pde_poll_actual_ps - Verify PDE power state reached target state
|
||||
* @dev: Pointer to the device for error logging.
|
||||
* @regmap: Register map for reading ACTUAL_PS register.
|
||||
* @function_id: SDCA function identifier.
|
||||
* @entity_id: SDCA entity identifier for the power domain.
|
||||
|
|
@ -389,11 +388,11 @@ static int entity_parse_ot(struct device *dev,
|
|||
* polling times out before reaching the target state, or a negative error code if
|
||||
* a register read fails.
|
||||
*/
|
||||
int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap,
|
||||
int sdca_asoc_pde_poll_actual_ps(struct regmap *regmap,
|
||||
int function_id, int entity_id,
|
||||
int from_ps, int to_ps,
|
||||
const struct sdca_pde_delay *pde_delays,
|
||||
int num_delays)
|
||||
int from_ps, int to_ps,
|
||||
const struct sdca_pde_delay *pde_delays,
|
||||
int num_delays)
|
||||
{
|
||||
static const int polls = 100;
|
||||
static const int default_poll_us = 1000;
|
||||
|
|
@ -451,14 +450,14 @@ static int entity_pde_event(struct snd_soc_dapm_widget *widget,
|
|||
return 0;
|
||||
}
|
||||
|
||||
ret = sdca_asoc_pde_poll_actual_ps(component->dev, component->regmap,
|
||||
ret = sdca_asoc_pde_poll_actual_ps(component->regmap,
|
||||
SDW_SDCA_CTL_FUNC(widget->reg),
|
||||
SDW_SDCA_CTL_ENT(widget->reg),
|
||||
from, to,
|
||||
entity->pde.max_delay,
|
||||
entity->pde.num_max_delay);
|
||||
if (ret)
|
||||
dev_err(component->dev, "%s: PDE transition %x -> %x failed, err=%d\n",
|
||||
dev_err(component->dev, "%s: pde transition %x -> %x failed: %d\n",
|
||||
entity->label, from, to, ret);
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ static int class_function_probe(struct auxiliary_device *auxdev,
|
|||
drv->core = core;
|
||||
drv->function = &sdev->function;
|
||||
|
||||
ret = sdca_parse_function(dev, core->sdw, drv->function);
|
||||
ret = sdca_parse_function(dev, drv->function);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ static void sdca_dev_release(struct device *dev)
|
|||
|
||||
/* alloc, init and add link devices */
|
||||
static struct sdca_dev *sdca_dev_register(struct device *parent,
|
||||
struct sdca_function_desc *function_desc)
|
||||
struct sdca_function_desc *function_desc,
|
||||
struct acpi_table_swft *swft)
|
||||
{
|
||||
struct sdca_dev *sdev;
|
||||
struct auxiliary_device *auxdev;
|
||||
|
|
@ -50,6 +51,7 @@ static struct sdca_dev *sdca_dev_register(struct device *parent,
|
|||
auxdev->dev.release = sdca_dev_release;
|
||||
|
||||
sdev->function.desc = function_desc;
|
||||
sdev->function.fdl_data.swft = swft;
|
||||
|
||||
rc = ida_alloc(&sdca_function_ida, GFP_KERNEL);
|
||||
if (rc < 0) {
|
||||
|
|
@ -99,7 +101,8 @@ int sdca_dev_register_functions(struct sdw_slave *slave)
|
|||
struct sdca_dev *func_dev;
|
||||
|
||||
func_dev = sdca_dev_register(&slave->dev,
|
||||
&sdca_data->function[i]);
|
||||
&sdca_data->function[i],
|
||||
sdca_data->swft);
|
||||
if (IS_ERR(func_dev)) {
|
||||
ret = PTR_ERR(func_dev);
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/byteorder/generic.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/device.h>
|
||||
|
|
@ -18,7 +19,6 @@
|
|||
#include <linux/types.h>
|
||||
#include <sound/sdca.h>
|
||||
#include <sound/sdca_function.h>
|
||||
#include <sound/sdca_hid.h>
|
||||
|
||||
/*
|
||||
* Should be long enough to encompass all the MIPI DisCo properties.
|
||||
|
|
@ -1365,90 +1365,76 @@ static int find_sdca_entity_ge(struct device *dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
find_sdca_entity_hide(struct device *dev, struct sdw_slave *sdw,
|
||||
struct fwnode_handle *function_node,
|
||||
struct fwnode_handle *entity_node, struct sdca_entity *entity)
|
||||
static int find_sdca_entity_hide(struct device *dev,
|
||||
struct fwnode_handle *entity_node,
|
||||
struct sdca_entity *entity)
|
||||
{
|
||||
struct sdca_entity_hide *hide = &entity->hide;
|
||||
unsigned int delay, *af_list = hide->af_number_list;
|
||||
int nval, ret;
|
||||
unsigned char *report_desc = NULL;
|
||||
int num_reports, ret;
|
||||
unsigned int delay;
|
||||
|
||||
ret = fwnode_property_read_u32(entity_node,
|
||||
"mipi-sdca-RxUMP-ownership-transition-max-delay", &delay);
|
||||
"mipi-sdca-RxUMP-ownership-transition-max-delay",
|
||||
&delay);
|
||||
if (!ret)
|
||||
hide->max_delay = delay;
|
||||
|
||||
nval = fwnode_property_count_u32(entity_node, "mipi-sdca-HIDTx-supported-report-ids");
|
||||
if (nval > 0) {
|
||||
hide->num_hidtx_ids = nval;
|
||||
num_reports = fwnode_property_count_u32(entity_node,
|
||||
"mipi-sdca-HIDTx-supported-report-ids");
|
||||
if (num_reports < 0 && num_reports != -EINVAL) {
|
||||
dev_err(dev, "%pfwP: failed to read hid tx ids: %d\n",
|
||||
entity_node, num_reports);
|
||||
return num_reports;
|
||||
} else if (num_reports > 0) {
|
||||
hide->num_hidtx_ids = num_reports;
|
||||
hide->hidtx_ids = devm_kcalloc(dev, hide->num_hidtx_ids,
|
||||
sizeof(*hide->hidtx_ids), GFP_KERNEL);
|
||||
if (!hide->hidtx_ids)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = fwnode_property_read_u32_array(entity_node,
|
||||
"mipi-sdca-HIDTx-supported-report-ids",
|
||||
hide->hidtx_ids,
|
||||
hide->num_hidtx_ids);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
fwnode_property_read_u32_array(entity_node,
|
||||
"mipi-sdca-HIDTx-supported-report-ids",
|
||||
hide->hidtx_ids, hide->num_hidtx_ids);
|
||||
}
|
||||
|
||||
nval = fwnode_property_count_u32(entity_node, "mipi-sdca-HIDRx-supported-report-ids");
|
||||
if (nval > 0) {
|
||||
hide->num_hidrx_ids = nval;
|
||||
num_reports = fwnode_property_count_u32(entity_node,
|
||||
"mipi-sdca-HIDRx-supported-report-ids");
|
||||
if (num_reports < 0 && num_reports != -EINVAL) {
|
||||
dev_err(dev, "%pfwP: failed to read hid rx ids: %d\n",
|
||||
entity_node, num_reports);
|
||||
return num_reports;
|
||||
} else if (num_reports > 0) {
|
||||
hide->num_hidrx_ids = num_reports;
|
||||
hide->hidrx_ids = devm_kcalloc(dev, hide->num_hidrx_ids,
|
||||
sizeof(*hide->hidrx_ids), GFP_KERNEL);
|
||||
if (!hide->hidrx_ids)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = fwnode_property_read_u32_array(entity_node,
|
||||
"mipi-sdca-HIDRx-supported-report-ids",
|
||||
hide->hidrx_ids,
|
||||
hide->num_hidrx_ids);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
fwnode_property_read_u32_array(entity_node,
|
||||
"mipi-sdca-HIDRx-supported-report-ids",
|
||||
hide->hidrx_ids, hide->num_hidrx_ids);
|
||||
}
|
||||
|
||||
nval = fwnode_property_count_u32(entity_node, "mipi-sdca-hide-related-audio-function-list");
|
||||
if (nval <= 0) {
|
||||
/*
|
||||
* FIXME: This should probably link to the actual sdca_function_data pointer,
|
||||
* but updating to do so should probably wait until we have a user.
|
||||
*/
|
||||
num_reports = fwnode_property_count_u32(entity_node,
|
||||
"mipi-sdca-hide-related-audio-function-list");
|
||||
if (num_reports <= 0) {
|
||||
dev_err(dev, "%pfwP: audio function numbers list missing: %d\n",
|
||||
entity_node, nval);
|
||||
entity_node, num_reports);
|
||||
return -EINVAL;
|
||||
} else if (nval > SDCA_MAX_FUNCTION_COUNT) {
|
||||
dev_err(dev, "%pfwP: maximum number of audio function exceeded\n", entity_node);
|
||||
} else if (num_reports > ARRAY_SIZE(hide->af_number_list)) {
|
||||
dev_err(dev, "%pfwP: maximum number of audio function exceeded\n",
|
||||
entity_node);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hide->hide_reside_function_num = nval;
|
||||
hide->hide_reside_function_num = num_reports;
|
||||
fwnode_property_read_u32_array(entity_node,
|
||||
"mipi-sdca-hide-related-audio-function-list", af_list, nval);
|
||||
|
||||
nval = fwnode_property_count_u8(function_node, "mipi-sdca-hid-descriptor");
|
||||
if (nval)
|
||||
fwnode_property_read_u8_array(function_node, "mipi-sdca-hid-descriptor",
|
||||
(u8 *)&hide->hid_desc, nval);
|
||||
|
||||
if (hide->hid_desc.bNumDescriptors) {
|
||||
nval = fwnode_property_count_u8(function_node, "mipi-sdca-report-descriptor");
|
||||
if (nval) {
|
||||
report_desc = devm_kzalloc(dev, nval, GFP_KERNEL);
|
||||
if (!report_desc)
|
||||
return -ENOMEM;
|
||||
hide->hid_report_desc = report_desc;
|
||||
fwnode_property_read_u8_array(function_node, "mipi-sdca-report-descriptor",
|
||||
report_desc, nval);
|
||||
|
||||
/* add HID device */
|
||||
ret = sdca_add_hid_device(dev, sdw, entity);
|
||||
if (ret) {
|
||||
dev_err(dev, "%pfwP: failed to add HID device: %d\n", entity_node, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
"mipi-sdca-hide-related-audio-function-list",
|
||||
hide->af_number_list, num_reports);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1475,8 +1461,7 @@ static int find_sdca_entity_xu(struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw,
|
||||
struct sdca_function_data *function,
|
||||
static int find_sdca_entity(struct device *dev, struct sdca_function_data *function,
|
||||
struct fwnode_handle *function_node,
|
||||
struct fwnode_handle *entity_node,
|
||||
struct sdca_entity *entity)
|
||||
|
|
@ -1528,8 +1513,7 @@ static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw,
|
|||
ret = find_sdca_entity_ge(dev, entity_node, entity);
|
||||
break;
|
||||
case SDCA_ENTITY_TYPE_HIDE:
|
||||
ret = find_sdca_entity_hide(dev, sdw, function_node,
|
||||
entity_node, entity);
|
||||
ret = find_sdca_entity_hide(dev, entity_node, entity);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -1544,8 +1528,7 @@ static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw,
|
||||
struct fwnode_handle *function_node,
|
||||
static int find_sdca_entities(struct device *dev, struct fwnode_handle *function_node,
|
||||
struct sdca_function_data *function)
|
||||
{
|
||||
struct sdca_entity *entities;
|
||||
|
|
@ -1596,7 +1579,7 @@ static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = find_sdca_entity(dev, sdw, function, function_node,
|
||||
ret = find_sdca_entity(dev, function, function_node,
|
||||
entity_node, &entities[i]);
|
||||
fwnode_handle_put(entity_node);
|
||||
if (ret)
|
||||
|
|
@ -2089,8 +2072,7 @@ static int find_sdca_clusters(struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw,
|
||||
struct fwnode_handle *function_node,
|
||||
static int find_sdca_filesets(struct device *dev, struct fwnode_handle *function_node,
|
||||
struct sdca_function_data *function)
|
||||
{
|
||||
static const int mult_fileset = 3;
|
||||
|
|
@ -2172,23 +2154,65 @@ static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw,
|
|||
set->files = files;
|
||||
}
|
||||
|
||||
function->fdl_data.swft = sdw->sdca_data.swft;
|
||||
function->fdl_data.num_sets = num_sets;
|
||||
function->fdl_data.sets = sets;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_sdca_hid(struct device *dev, struct fwnode_handle *function_node,
|
||||
struct sdca_function_data *function)
|
||||
{
|
||||
int num_desc;
|
||||
|
||||
num_desc = fwnode_property_count_u8(function_node, "mipi-sdca-hid-descriptor");
|
||||
if (!num_desc) {
|
||||
return 0;
|
||||
} else if (num_desc < 0) {
|
||||
dev_err(dev, "%pfwP: failed to read hid descriptor: %d\n",
|
||||
function_node, num_desc);
|
||||
return num_desc;
|
||||
} else if (num_desc > sizeof(function->hid.desc)) {
|
||||
dev_err(dev, "%pfwP: hid descriptor too large: %d\n",
|
||||
function_node, num_desc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fwnode_property_read_u8_array(function_node, "mipi-sdca-hid-descriptor",
|
||||
(u8 *)&function->hid.desc, num_desc);
|
||||
|
||||
if (!function->hid.desc.bNumDescriptors)
|
||||
return 0;
|
||||
|
||||
num_desc = fwnode_property_count_u8(function_node, "mipi-sdca-report-descriptor");
|
||||
if (num_desc <= 0) {
|
||||
dev_err(dev, "%pfwP: failed to read report descriptor: %d\n",
|
||||
function_node, num_desc);
|
||||
|
||||
if (!num_desc)
|
||||
return -EINVAL;
|
||||
|
||||
return num_desc;
|
||||
}
|
||||
|
||||
function->hid.report_desc = devm_kzalloc(dev, num_desc, GFP_KERNEL);
|
||||
if (!function->hid.report_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
fwnode_property_read_u8_array(function_node, "mipi-sdca-report-descriptor",
|
||||
function->hid.report_desc, num_desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sdca_parse_function - parse ACPI DisCo for a Function
|
||||
* @dev: Pointer to device against which function data will be allocated.
|
||||
* @sdw: SoundWire slave device to be processed.
|
||||
* @function: Pointer to the Function information, to be populated.
|
||||
*
|
||||
* Return: Returns 0 for success.
|
||||
*/
|
||||
int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
|
||||
struct sdca_function_data *function)
|
||||
int sdca_parse_function(struct device *dev, struct sdca_function_data *function)
|
||||
{
|
||||
struct fwnode_handle *node = function->desc->node;
|
||||
u32 tmp;
|
||||
|
|
@ -2214,7 +2238,7 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = find_sdca_entities(dev, sdw, node, function);
|
||||
ret = find_sdca_entities(dev, node, function);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -2226,10 +2250,20 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = find_sdca_filesets(dev, sdw, node, function);
|
||||
ret = find_sdca_filesets(dev, node, function);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (function->desc->type) {
|
||||
case SDCA_FUNCTION_TYPE_HID:
|
||||
ret = find_sdca_hid(dev, node, function);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA");
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <sound/sdca.h>
|
||||
#include <sound/sdca_function.h>
|
||||
|
|
@ -23,18 +24,18 @@
|
|||
|
||||
static int sdwhid_parse(struct hid_device *hid)
|
||||
{
|
||||
struct sdca_entity *entity = hid->driver_data;
|
||||
struct sdca_function_data *function = hid->driver_data;
|
||||
unsigned int rsize;
|
||||
int ret;
|
||||
|
||||
rsize = le16_to_cpu(entity->hide.hid_desc.rpt_desc.wDescriptorLength);
|
||||
rsize = le16_to_cpu(function->hid.desc.rpt_desc.wDescriptorLength);
|
||||
|
||||
if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
|
||||
dev_err(&hid->dev, "invalid size of report descriptor (%u)\n", rsize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = hid_parse_report(hid, entity->hide.hid_report_desc, rsize);
|
||||
ret = hid_parse_report(hid, function->hid.report_desc, rsize);
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
|
@ -85,10 +86,16 @@ static const struct hid_ll_driver sdw_hid_driver = {
|
|||
.raw_request = sdwhid_raw_request,
|
||||
};
|
||||
|
||||
int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
|
||||
struct sdca_entity *entity)
|
||||
/**
|
||||
* sdca_add_hid_device - create a new SDCA HID device
|
||||
* @interrupt: Pointer to the SDCA interrupt information structure.
|
||||
*
|
||||
* Return: Zero on success, and a negative error code on failure.
|
||||
*/
|
||||
int sdca_add_hid_device(struct sdca_interrupt *interrupt)
|
||||
{
|
||||
struct sdw_bus *bus = sdw->bus;
|
||||
struct device *dev = interrupt->dev;
|
||||
struct sdca_function_data *function = interrupt->function;
|
||||
struct hid_device *hid;
|
||||
int ret;
|
||||
|
||||
|
|
@ -100,16 +107,13 @@ int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
|
|||
|
||||
hid->dev.parent = dev;
|
||||
hid->bus = BUS_SDW;
|
||||
hid->version = le16_to_cpu(entity->hide.hid_desc.bcdHID);
|
||||
hid->version = le16_to_cpu(function->hid.desc.bcdHID);
|
||||
|
||||
snprintf(hid->name, sizeof(hid->name),
|
||||
"HID sdw:%01x:%01x:%04x:%04x:%02x",
|
||||
bus->controller_id, bus->link_id, sdw->id.mfg_id,
|
||||
sdw->id.part_id, sdw->id.class_id);
|
||||
strscpy(hid->phys, dev_name(dev));
|
||||
snprintf(hid->name, sizeof(hid->name), "SDCA %s:%02x",
|
||||
function->desc->name, function->desc->adr);
|
||||
|
||||
snprintf(hid->phys, sizeof(hid->phys), "%s", dev->bus->name);
|
||||
|
||||
hid->driver_data = entity;
|
||||
hid->driver_data = function;
|
||||
|
||||
ret = hid_add_device(hid);
|
||||
if (ret && ret != -ENODEV) {
|
||||
|
|
@ -118,12 +122,24 @@ int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
|
|||
return ret;
|
||||
}
|
||||
|
||||
entity->hide.hid = hid;
|
||||
interrupt->priv = hid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA");
|
||||
|
||||
/**
|
||||
* sdca_destroy_hid_device - destroy the HID device
|
||||
* @interrupt: Pointer to the SDCA interrupt information structure.
|
||||
*/
|
||||
void sdca_destroy_hid_device(struct sdca_interrupt *interrupt)
|
||||
{
|
||||
struct hid_device *hid = interrupt->priv;
|
||||
|
||||
hid_destroy_device(hid);
|
||||
}
|
||||
EXPORT_SYMBOL_NS(sdca_destroy_hid_device, "SND_SOC_SDCA");
|
||||
|
||||
/**
|
||||
* sdca_hid_process_report - read a HID event from the device and report
|
||||
* @interrupt: Pointer to the SDCA interrupt information structure.
|
||||
|
|
@ -133,7 +149,7 @@ EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA");
|
|||
int sdca_hid_process_report(struct sdca_interrupt *interrupt)
|
||||
{
|
||||
struct device *dev = interrupt->dev;
|
||||
struct hid_device *hid = interrupt->entity->hide.hid;
|
||||
struct hid_device *hid = interrupt->priv;
|
||||
void *val __free(kfree) = NULL;
|
||||
int len, ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -487,6 +487,12 @@ int sdca_irq_populate_early(struct device *dev, struct regmap *regmap,
|
|||
}
|
||||
break;
|
||||
case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER):
|
||||
interrupt->free_priv = sdca_destroy_hid_device;
|
||||
|
||||
ret = sdca_add_hid_device(interrupt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
interrupt->handler = hid_handler;
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user