sound: Add uclass operations for beeping
Some audio codecs such as Intel HDA do not need to use digital data to play sounds, but instead have a way to emit beeps. Add this interface as an option. If the beep interface is not supported, then the sound uclass falls back to the I2S interface. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
parent
e65f9ef9f2
commit
2850266965
@ -161,6 +161,22 @@ int sandbox_get_setup_called(struct udevice *dev);
|
||||
*/
|
||||
int sandbox_get_sound_sum(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* sandbox_set_allow_beep() - Set whether the 'beep' interface is supported
|
||||
*
|
||||
* @dev: Device to update
|
||||
* @allow: true to allow the start_beep() method, false to disallow it
|
||||
*/
|
||||
void sandbox_set_allow_beep(struct udevice *dev, bool allow);
|
||||
|
||||
/**
|
||||
* sandbox_get_beep_frequency() - Get the frequency of the current beep
|
||||
*
|
||||
* @dev: Device to check
|
||||
* @return frequency of beep, if there is an active beep, else 0
|
||||
*/
|
||||
int sandbox_get_beep_frequency(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* sandbox_get_pch_spi_protect() - Get the PCI SPI protection status
|
||||
*
|
||||
|
@ -24,7 +24,9 @@ struct sandbox_i2s_priv {
|
||||
|
||||
struct sandbox_sound_priv {
|
||||
int setup_called;
|
||||
int sum; /* Use to sum the provided audio data */
|
||||
int sum; /* Use to sum the provided audio data */
|
||||
bool allow_beep; /* true to allow the start_beep() interface */
|
||||
int frequency_hz; /* Beep frequency if active, else 0 */
|
||||
};
|
||||
|
||||
void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep,
|
||||
@ -61,6 +63,20 @@ int sandbox_get_sound_sum(struct udevice *dev)
|
||||
return priv->sum;
|
||||
}
|
||||
|
||||
void sandbox_set_allow_beep(struct udevice *dev, bool allow)
|
||||
{
|
||||
struct sandbox_sound_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->allow_beep = allow;
|
||||
}
|
||||
|
||||
int sandbox_get_beep_frequency(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_sound_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return priv->frequency_hz;
|
||||
}
|
||||
|
||||
static int sandbox_codec_set_params(struct udevice *dev, int interface,
|
||||
int rate, int mclk_freq,
|
||||
int bits_per_sample, uint channels)
|
||||
@ -128,6 +144,28 @@ static int sandbox_sound_play(struct udevice *dev, void *data, uint data_size)
|
||||
return i2s_tx_data(uc_priv->i2s, data, data_size);
|
||||
}
|
||||
|
||||
int sandbox_sound_start_beep(struct udevice *dev, int frequency_hz)
|
||||
{
|
||||
struct sandbox_sound_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (!priv->allow_beep)
|
||||
return -ENOSYS;
|
||||
priv->frequency_hz = frequency_hz;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sandbox_sound_stop_beep(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_sound_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (!priv->allow_beep)
|
||||
return -ENOSYS;
|
||||
priv->frequency_hz = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_sound_probe(struct udevice *dev)
|
||||
{
|
||||
return sound_find_codec_i2s(dev);
|
||||
@ -169,8 +207,10 @@ U_BOOT_DRIVER(sandbox_i2s) = {
|
||||
};
|
||||
|
||||
static const struct sound_ops sandbox_sound_ops = {
|
||||
.setup = sandbox_sound_setup,
|
||||
.play = sandbox_sound_play,
|
||||
.setup = sandbox_sound_setup,
|
||||
.play = sandbox_sound_play,
|
||||
.start_beep = sandbox_sound_start_beep,
|
||||
.stop_beep = sandbox_sound_stop_beep,
|
||||
};
|
||||
|
||||
static const struct udevice_id sandbox_sound_ids[] = {
|
||||
|
@ -31,10 +31,30 @@ int sound_play(struct udevice *dev, void *data, uint data_size)
|
||||
return ops->play(dev, data, data_size);
|
||||
}
|
||||
|
||||
int sound_start_beep(struct udevice *dev, int frequency_hz)
|
||||
{
|
||||
struct sound_ops *ops = sound_get_ops(dev);
|
||||
|
||||
if (!ops->start_beep)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->start_beep(dev, frequency_hz);
|
||||
}
|
||||
|
||||
int sound_stop_beep(struct udevice *dev)
|
||||
{
|
||||
struct sound_ops *ops = sound_get_ops(dev);
|
||||
|
||||
if (!ops->stop_beep)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->stop_beep(dev);
|
||||
}
|
||||
|
||||
int sound_beep(struct udevice *dev, int msecs, int frequency_hz)
|
||||
{
|
||||
struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct i2s_uc_priv *i2s_uc_priv = dev_get_uclass_priv(uc_priv->i2s);
|
||||
struct i2s_uc_priv *i2s_uc_priv;
|
||||
unsigned short *data;
|
||||
uint data_size;
|
||||
int ret;
|
||||
@ -43,7 +63,19 @@ int sound_beep(struct udevice *dev, int msecs, int frequency_hz)
|
||||
if (ret && ret != -EALREADY)
|
||||
return ret;
|
||||
|
||||
/* Try using the beep interface if available */
|
||||
ret = sound_start_beep(dev, frequency_hz);
|
||||
if (ret != -ENOSYS) {
|
||||
if (ret)
|
||||
return ret;
|
||||
mdelay(msecs);
|
||||
ret = sound_stop_beep(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Buffer length computation */
|
||||
i2s_uc_priv = dev_get_uclass_priv(uc_priv->i2s);
|
||||
data_size = i2s_uc_priv->samplingrate * i2s_uc_priv->channels;
|
||||
data_size *= (i2s_uc_priv->bitspersample / SOUND_BITS_IN_BYTE);
|
||||
data = malloc(data_size);
|
||||
|
@ -67,6 +67,28 @@ struct sound_ops {
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int (*play)(struct udevice *dev, void *data, uint data_size);
|
||||
|
||||
/**
|
||||
* start_beep() - Start beeping (optional)
|
||||
*
|
||||
* This tells the sound hardware to start a beep. It will continue until
|
||||
* stopped by sound_stop_beep().
|
||||
*
|
||||
* @dev: Sound device
|
||||
* @frequency_hz: Beep frequency in hertz
|
||||
* @return if OK, -ENOSYS if not supported, -ve on error
|
||||
*/
|
||||
int (*start_beep)(struct udevice *dev, int frequency_hz);
|
||||
|
||||
/**
|
||||
* stop_beep() - Stop beeping (optional)
|
||||
*
|
||||
* This tells the sound hardware to stop a previously started beep.
|
||||
*
|
||||
* @dev: Sound device
|
||||
* @return if OK, -ve on error
|
||||
*/
|
||||
int (*stop_beep)(struct udevice *dev);
|
||||
};
|
||||
|
||||
#define sound_get_ops(dev) ((struct sound_ops *)(dev)->driver->ops)
|
||||
@ -86,6 +108,28 @@ int sound_setup(struct udevice *dev);
|
||||
*/
|
||||
int sound_beep(struct udevice *dev, int msecs, int frequency_hz);
|
||||
|
||||
/**
|
||||
* sound_start_beep() - Start beeping
|
||||
*
|
||||
* This tells the sound hardware to start a beep. It will continue until stopped
|
||||
* by sound_stop_beep().
|
||||
*
|
||||
* @dev: Sound device
|
||||
* @frequency_hz: Beep frequency in hertz
|
||||
* @return if OK, -ve on error
|
||||
*/
|
||||
int sound_start_beep(struct udevice *dev, int frequency_hz);
|
||||
|
||||
/**
|
||||
* sound_stop_beep() - Stop beeping
|
||||
*
|
||||
* This tells the sound hardware to stop a previously started beep.
|
||||
*
|
||||
* @dev: Sound device
|
||||
* @return if OK, -ve on error
|
||||
*/
|
||||
int sound_stop_beep(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* sound_find_codec_i2s() - Called by sound drivers to locate codec and i2s
|
||||
*
|
||||
|
@ -32,3 +32,24 @@ static int dm_test_sound(struct unit_test_state *uts)
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_sound, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
||||
/* Test of the 'start beep' operations */
|
||||
static int dm_test_sound_beep(struct unit_test_state *uts)
|
||||
{
|
||||
struct udevice *dev;
|
||||
|
||||
/* check probe success */
|
||||
ut_assertok(uclass_first_device_err(UCLASS_SOUND, &dev));
|
||||
ut_asserteq(-ENOSYS, sound_start_beep(dev, 100));
|
||||
ut_asserteq(0, sandbox_get_beep_frequency(dev));
|
||||
|
||||
sandbox_set_allow_beep(dev, true);
|
||||
ut_asserteq(0, sound_start_beep(dev, 100));
|
||||
ut_asserteq(100, sandbox_get_beep_frequency(dev));
|
||||
|
||||
ut_asserteq(0, sound_stop_beep(dev));
|
||||
ut_asserteq(0, sandbox_get_beep_frequency(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_sound_beep, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
Loading…
Reference in New Issue
Block a user