brintos

brintos / linux-shallow public Read only

0
0
Text · 2.5 KiB · 66bd4da Raw
108 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *   UAC3 Power Domain state management functions4 */5 6#include <linux/slab.h>7#include <linux/usb.h>8#include <linux/usb/audio.h>9#include <linux/usb/audio-v2.h>10#include <linux/usb/audio-v3.h>11 12#include "usbaudio.h"13#include "helper.h"14#include "power.h"15 16struct snd_usb_power_domain *17snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface,18			  unsigned char id)19{20	struct snd_usb_power_domain *pd;21	void *p;22 23	pd = kzalloc(sizeof(*pd), GFP_KERNEL);24	if (!pd)25		return NULL;26 27	p = NULL;28	while ((p = snd_usb_find_csint_desc(ctrl_iface->extra,29					    ctrl_iface->extralen,30					    p, UAC3_POWER_DOMAIN)) != NULL) {31		struct uac3_power_domain_descriptor *pd_desc = p;32		int i;33 34		if (!snd_usb_validate_audio_desc(p, UAC_VERSION_3))35			continue;36		for (i = 0; i < pd_desc->bNrEntities; i++) {37			if (pd_desc->baEntityID[i] == id) {38				pd->pd_id = pd_desc->bPowerDomainID;39				pd->pd_d1d0_rec =40					le16_to_cpu(pd_desc->waRecoveryTime1);41				pd->pd_d2d0_rec =42					le16_to_cpu(pd_desc->waRecoveryTime2);43				pd->ctrl_iface = ctrl_iface;44				return pd;45			}46		}47	}48 49	kfree(pd);50	return NULL;51}52 53int snd_usb_power_domain_set(struct snd_usb_audio *chip,54			     struct snd_usb_power_domain *pd,55			     unsigned char state)56{57	struct usb_device *dev = chip->dev;58	unsigned char current_state;59	int err, idx;60 61	idx = snd_usb_ctrl_intf(pd->ctrl_iface) | (pd->pd_id << 8);62 63	err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),64			      UAC2_CS_CUR,65			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,66			      UAC3_AC_POWER_DOMAIN_CONTROL << 8, idx,67			      &current_state, sizeof(current_state));68	if (err < 0) {69		dev_err(&dev->dev, "Can't get UAC3 power state for id %d\n",70			pd->pd_id);71		return err;72	}73 74	if (current_state == state) {75		dev_dbg(&dev->dev, "UAC3 power domain id %d already in state %d\n",76			pd->pd_id, state);77		return 0;78	}79 80	err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR,81			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,82			      UAC3_AC_POWER_DOMAIN_CONTROL << 8, idx,83			      &state, sizeof(state));84	if (err < 0) {85		dev_err(&dev->dev, "Can't set UAC3 power state to %d for id %d\n",86			state, pd->pd_id);87		return err;88	}89 90	if (state == UAC3_PD_STATE_D0) {91		switch (current_state) {92		case UAC3_PD_STATE_D2:93			udelay(pd->pd_d2d0_rec * 50);94			break;95		case UAC3_PD_STATE_D1:96			udelay(pd->pd_d1d0_rec * 50);97			break;98		default:99			return -EINVAL;100		}101	}102 103	dev_dbg(&dev->dev, "UAC3 power domain id %d change to state %d\n",104		pd->pd_id, state);105 106	return 0;107}108