Linux Audio

Check our new training course

Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *   UAC3 Power Domain state management functions
  4 */
  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				return pd;
 44			}
 45		}
 46	}
 47
 48	kfree(pd);
 49	return NULL;
 50}
 51
 52int snd_usb_power_domain_set(struct snd_usb_audio *chip,
 53			     struct snd_usb_power_domain *pd,
 54			     unsigned char state)
 55{
 56	struct usb_device *dev = chip->dev;
 57	unsigned char current_state;
 58	int err, idx;
 59
 60	idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8);
 61
 62	err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
 63			      UAC2_CS_CUR,
 64			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
 65			      UAC3_AC_POWER_DOMAIN_CONTROL << 8, idx,
 66			      &current_state, sizeof(current_state));
 67	if (err < 0) {
 68		dev_err(&dev->dev, "Can't get UAC3 power state for id %d\n",
 69			pd->pd_id);
 70		return err;
 71	}
 72
 73	if (current_state == state) {
 74		dev_dbg(&dev->dev, "UAC3 power domain id %d already in state %d\n",
 75			pd->pd_id, state);
 76		return 0;
 77	}
 78
 79	err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR,
 80			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
 81			      UAC3_AC_POWER_DOMAIN_CONTROL << 8, idx,
 82			      &state, sizeof(state));
 83	if (err < 0) {
 84		dev_err(&dev->dev, "Can't set UAC3 power state to %d for id %d\n",
 85			state, pd->pd_id);
 86		return err;
 87	}
 88
 89	if (state == UAC3_PD_STATE_D0) {
 90		switch (current_state) {
 91		case UAC3_PD_STATE_D2:
 92			udelay(pd->pd_d2d0_rec * 50);
 93			break;
 94		case UAC3_PD_STATE_D1:
 95			udelay(pd->pd_d1d0_rec * 50);
 96			break;
 97		default:
 98			return -EINVAL;
 99		}
100	}
101
102	dev_dbg(&dev->dev, "UAC3 power domain id %d change to state %d\n",
103		pd->pd_id, state);
104
105	return 0;
106}
v6.9.4
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *   UAC3 Power Domain state management functions
  4 */
  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				return pd;
 44			}
 45		}
 46	}
 47
 48	kfree(pd);
 49	return NULL;
 50}
 51
 52int snd_usb_power_domain_set(struct snd_usb_audio *chip,
 53			     struct snd_usb_power_domain *pd,
 54			     unsigned char state)
 55{
 56	struct usb_device *dev = chip->dev;
 57	unsigned char current_state;
 58	int err, idx;
 59
 60	idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8);
 61
 62	err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
 63			      UAC2_CS_CUR,
 64			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
 65			      UAC3_AC_POWER_DOMAIN_CONTROL << 8, idx,
 66			      &current_state, sizeof(current_state));
 67	if (err < 0) {
 68		dev_err(&dev->dev, "Can't get UAC3 power state for id %d\n",
 69			pd->pd_id);
 70		return err;
 71	}
 72
 73	if (current_state == state) {
 74		dev_dbg(&dev->dev, "UAC3 power domain id %d already in state %d\n",
 75			pd->pd_id, state);
 76		return 0;
 77	}
 78
 79	err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR,
 80			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
 81			      UAC3_AC_POWER_DOMAIN_CONTROL << 8, idx,
 82			      &state, sizeof(state));
 83	if (err < 0) {
 84		dev_err(&dev->dev, "Can't set UAC3 power state to %d for id %d\n",
 85			state, pd->pd_id);
 86		return err;
 87	}
 88
 89	if (state == UAC3_PD_STATE_D0) {
 90		switch (current_state) {
 91		case UAC3_PD_STATE_D2:
 92			udelay(pd->pd_d2d0_rec * 50);
 93			break;
 94		case UAC3_PD_STATE_D1:
 95			udelay(pd->pd_d1d0_rec * 50);
 96			break;
 97		default:
 98			return -EINVAL;
 99		}
100	}
101
102	dev_dbg(&dev->dev, "UAC3 power domain id %d change to state %d\n",
103		pd->pd_id, state);
104
105	return 0;
106}