2019-05-29 16:57:59 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2014-04-25 22:45:24 +09:00
/*
* bebob_focusrite . c - a part of driver for BeBoB based devices
*
* Copyright ( c ) 2013 - 2014 Takashi Sakamoto
*/
# include "./bebob.h"
# define ANA_IN "Analog In"
# define DIG_IN "Digital In"
# define ANA_OUT "Analog Out"
# define DIG_OUT "Digital Out"
# define STM_IN "Stream In"
2014-05-28 00:14:42 +09:00
# define SAFFIRE_ADDRESS_BASE 0x000100000000ULL
2014-04-25 22:45:24 +09:00
2014-05-28 00:14:42 +09:00
# define SAFFIRE_OFFSET_CLOCK_SOURCE 0x00f8
# define SAFFIREPRO_OFFSET_CLOCK_SOURCE 0x0174
2014-04-25 22:45:24 +09:00
/* whether sync to external device or not */
2014-05-28 00:14:42 +09:00
# define SAFFIRE_OFFSET_CLOCK_SYNC_EXT 0x013c
# define SAFFIRE_LE_OFFSET_CLOCK_SYNC_EXT 0x0432
# define SAFFIREPRO_OFFSET_CLOCK_SYNC_EXT 0x0164
2014-04-25 22:45:24 +09:00
# define SAFFIRE_CLOCK_SOURCE_INTERNAL 0
# define SAFFIRE_CLOCK_SOURCE_SPDIF 1
2014-10-25 13:40:41 +02:00
/* clock sources as returned from register of Saffire Pro 10 and 26 */
2019-11-03 00:09:20 +09:00
# define SAFFIREPRO_CLOCK_SOURCE_SELECT_MASK 0x000000ff
# define SAFFIREPRO_CLOCK_SOURCE_DETECT_MASK 0x0000ff00
2014-04-25 22:45:24 +09:00
# define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0
2014-10-25 13:40:41 +02:00
# define SAFFIREPRO_CLOCK_SOURCE_SKIP 1 /* never used on hardware */
2014-04-25 22:45:24 +09:00
# define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2
2014-10-25 13:40:41 +02:00
# define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 /* not used on s.pro. 10 */
# define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 /* not used on s.pro. 10 */
2014-04-25 22:45:24 +09:00
# define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 5
2014-10-25 13:40:41 +02:00
# define SAFFIREPRO_CLOCK_SOURCE_COUNT 6
2014-04-25 22:45:24 +09:00
/* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */
2014-05-28 00:14:42 +09:00
# define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a4
2014-04-25 22:45:24 +09:00
/* saffirepro has its own parameter for sampling frequency */
2014-05-28 00:14:42 +09:00
# define SAFFIREPRO_RATE_NOREBOOT 0x01cc
2014-04-25 22:45:24 +09:00
/* index is the value for this register */
static const unsigned int rates [ ] = {
[ 0 ] = 0 ,
[ 1 ] = 44100 ,
[ 2 ] = 48000 ,
[ 3 ] = 88200 ,
[ 4 ] = 96000 ,
[ 5 ] = 176400 ,
[ 6 ] = 192000
} ;
/* saffire(no label)/saffire LE has metering */
2014-05-28 00:14:42 +09:00
# define SAFFIRE_OFFSET_METER 0x0100
# define SAFFIRE_LE_OFFSET_METER 0x0168
2014-04-25 22:45:24 +09:00
static inline int
saffire_read_block ( struct snd_bebob * bebob , u64 offset ,
u32 * buf , unsigned int size )
{
unsigned int i ;
int err ;
__be32 * tmp = ( __be32 * ) buf ;
err = snd_fw_transaction ( bebob - > unit , TCODE_READ_BLOCK_REQUEST ,
SAFFIRE_ADDRESS_BASE + offset ,
tmp , size , 0 ) ;
if ( err < 0 )
goto end ;
for ( i = 0 ; i < size / sizeof ( u32 ) ; i + + )
buf [ i ] = be32_to_cpu ( tmp [ i ] ) ;
end :
return err ;
}
static inline int
saffire_read_quad ( struct snd_bebob * bebob , u64 offset , u32 * value )
{
int err ;
__be32 tmp ;
err = snd_fw_transaction ( bebob - > unit , TCODE_READ_QUADLET_REQUEST ,
SAFFIRE_ADDRESS_BASE + offset ,
& tmp , sizeof ( __be32 ) , 0 ) ;
if ( err < 0 )
goto end ;
* value = be32_to_cpu ( tmp ) ;
end :
return err ;
}
static inline int
saffire_write_quad ( struct snd_bebob * bebob , u64 offset , u32 value )
{
__be32 data = cpu_to_be32 ( value ) ;
return snd_fw_transaction ( bebob - > unit , TCODE_WRITE_QUADLET_REQUEST ,
SAFFIRE_ADDRESS_BASE + offset ,
& data , sizeof ( __be32 ) , 0 ) ;
}
2017-08-22 22:58:15 +09:00
static const enum snd_bebob_clock_type saffirepro_10_clk_src_types [ ] = {
2015-06-14 12:49:29 +09:00
SND_BEBOB_CLOCK_TYPE_INTERNAL ,
SND_BEBOB_CLOCK_TYPE_EXTERNAL , /* S/PDIF */
SND_BEBOB_CLOCK_TYPE_EXTERNAL , /* Word Clock */
} ;
2017-08-22 22:58:15 +09:00
static const enum snd_bebob_clock_type saffirepro_26_clk_src_types [ ] = {
2015-06-14 12:49:29 +09:00
SND_BEBOB_CLOCK_TYPE_INTERNAL ,
SND_BEBOB_CLOCK_TYPE_EXTERNAL , /* S/PDIF */
SND_BEBOB_CLOCK_TYPE_EXTERNAL , /* ADAT1 */
SND_BEBOB_CLOCK_TYPE_EXTERNAL , /* ADAT2 */
SND_BEBOB_CLOCK_TYPE_EXTERNAL , /* Word Clock */
} ;
2014-10-25 13:40:41 +02:00
/* Value maps between registers and labels for SaffirePro 10/26. */
static const signed char saffirepro_clk_maps [ ] [ SAFFIREPRO_CLOCK_SOURCE_COUNT ] = {
/* SaffirePro 10 */
[ 0 ] = {
[ SAFFIREPRO_CLOCK_SOURCE_INTERNAL ] = 0 ,
[ SAFFIREPRO_CLOCK_SOURCE_SKIP ] = - 1 , /* not supported */
[ SAFFIREPRO_CLOCK_SOURCE_SPDIF ] = 1 ,
[ SAFFIREPRO_CLOCK_SOURCE_ADAT1 ] = - 1 , /* not supported */
[ SAFFIREPRO_CLOCK_SOURCE_ADAT2 ] = - 1 , /* not supported */
[ SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK ] = 2 ,
} ,
/* SaffirePro 26 */
[ 1 ] = {
[ SAFFIREPRO_CLOCK_SOURCE_INTERNAL ] = 0 ,
[ SAFFIREPRO_CLOCK_SOURCE_SKIP ] = - 1 , /* not supported */
[ SAFFIREPRO_CLOCK_SOURCE_SPDIF ] = 1 ,
[ SAFFIREPRO_CLOCK_SOURCE_ADAT1 ] = 2 ,
[ SAFFIREPRO_CLOCK_SOURCE_ADAT2 ] = 3 ,
[ SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK ] = 4 ,
}
2014-04-25 22:45:24 +09:00
} ;
2014-10-25 13:40:41 +02:00
2014-04-25 22:45:24 +09:00
static int
saffirepro_both_clk_freq_get ( struct snd_bebob * bebob , unsigned int * rate )
{
u32 id ;
int err ;
err = saffire_read_quad ( bebob , SAFFIREPRO_RATE_NOREBOOT , & id ) ;
if ( err < 0 )
goto end ;
if ( id > = ARRAY_SIZE ( rates ) )
err = - EIO ;
else
* rate = rates [ id ] ;
end :
return err ;
}
static int
saffirepro_both_clk_freq_set ( struct snd_bebob * bebob , unsigned int rate )
{
u32 id ;
for ( id = 0 ; id < ARRAY_SIZE ( rates ) ; id + + ) {
if ( rates [ id ] = = rate )
break ;
}
if ( id = = ARRAY_SIZE ( rates ) )
return - EINVAL ;
return saffire_write_quad ( bebob , SAFFIREPRO_RATE_NOREBOOT , id ) ;
}
2014-10-25 13:40:41 +02:00
/*
* query hardware for current clock source , return our internally
* used clock index in * id , depending on hardware .
*/
2014-04-25 22:45:24 +09:00
static int
saffirepro_both_clk_src_get ( struct snd_bebob * bebob , unsigned int * id )
{
int err ;
2014-10-25 13:40:41 +02:00
u32 value ; /* clock source read from hw register */
const signed char * map ;
2014-04-25 22:45:24 +09:00
err = saffire_read_quad ( bebob , SAFFIREPRO_OFFSET_CLOCK_SOURCE , & value ) ;
if ( err < 0 )
goto end ;
2014-10-25 13:40:41 +02:00
/* depending on hardware, use a different mapping */
2015-06-14 12:49:29 +09:00
if ( bebob - > spec - > clock - > types = = saffirepro_10_clk_src_types )
2014-10-25 13:40:41 +02:00
map = saffirepro_clk_maps [ 0 ] ;
else
map = saffirepro_clk_maps [ 1 ] ;
/* In a case that this driver cannot handle the value of register. */
2019-11-03 00:09:20 +09:00
value & = SAFFIREPRO_CLOCK_SOURCE_SELECT_MASK ;
2014-10-25 13:40:41 +02:00
if ( value > = SAFFIREPRO_CLOCK_SOURCE_COUNT | | map [ value ] < 0 ) {
err = - EIO ;
goto end ;
2014-04-25 22:45:24 +09:00
}
2014-10-25 13:40:41 +02:00
* id = ( unsigned int ) map [ value ] ;
2014-04-25 22:45:24 +09:00
end :
return err ;
}
2015-10-11 08:10:55 +02:00
const struct snd_bebob_spec saffire_le_spec ;
2017-08-22 22:58:15 +09:00
static const enum snd_bebob_clock_type saffire_both_clk_src_types [ ] = {
2015-06-14 12:49:29 +09:00
SND_BEBOB_CLOCK_TYPE_INTERNAL ,
SND_BEBOB_CLOCK_TYPE_EXTERNAL ,
} ;
2014-04-25 22:45:24 +09:00
static int
saffire_both_clk_src_get ( struct snd_bebob * bebob , unsigned int * id )
{
int err ;
u32 value ;
err = saffire_read_quad ( bebob , SAFFIRE_OFFSET_CLOCK_SOURCE , & value ) ;
if ( err > = 0 )
* id = 0xff & value ;
return err ;
} ;
2014-10-21 08:26:10 +02:00
static const char * const saffire_le_meter_labels [ ] = {
2014-04-25 22:45:24 +09:00
ANA_IN , ANA_IN , DIG_IN ,
ANA_OUT , ANA_OUT , ANA_OUT , ANA_OUT ,
STM_IN , STM_IN
} ;
2014-10-21 08:26:10 +02:00
static const char * const saffire_meter_labels [ ] = {
2014-04-25 22:45:24 +09:00
ANA_IN , ANA_IN ,
STM_IN , STM_IN , STM_IN , STM_IN , STM_IN ,
} ;
static int
saffire_meter_get ( struct snd_bebob * bebob , u32 * buf , unsigned int size )
{
2015-10-11 08:10:55 +02:00
const struct snd_bebob_meter_spec * spec = bebob - > spec - > meter ;
2014-04-25 22:45:24 +09:00
unsigned int channels ;
u64 offset ;
int err ;
if ( spec - > labels = = saffire_le_meter_labels )
offset = SAFFIRE_LE_OFFSET_METER ;
else
offset = SAFFIRE_OFFSET_METER ;
channels = spec - > num * 2 ;
if ( size < channels * sizeof ( u32 ) )
return - EIO ;
err = saffire_read_block ( bebob , offset , buf , size ) ;
if ( err > = 0 & & spec - > labels = = saffire_le_meter_labels ) {
swap ( buf [ 1 ] , buf [ 3 ] ) ;
swap ( buf [ 2 ] , buf [ 3 ] ) ;
swap ( buf [ 3 ] , buf [ 4 ] ) ;
swap ( buf [ 7 ] , buf [ 10 ] ) ;
swap ( buf [ 8 ] , buf [ 10 ] ) ;
swap ( buf [ 9 ] , buf [ 11 ] ) ;
swap ( buf [ 11 ] , buf [ 12 ] ) ;
swap ( buf [ 15 ] , buf [ 16 ] ) ;
}
return err ;
}
2015-10-11 08:10:55 +02:00
static const struct snd_bebob_rate_spec saffirepro_both_rate_spec = {
2014-04-25 22:45:24 +09:00
. get = & saffirepro_both_clk_freq_get ,
. set = & saffirepro_both_clk_freq_set ,
} ;
/* Saffire Pro 26 I/O */
2015-10-11 08:10:55 +02:00
static const struct snd_bebob_clock_spec saffirepro_26_clk_spec = {
2015-06-14 12:49:29 +09:00
. num = ARRAY_SIZE ( saffirepro_26_clk_src_types ) ,
. types = saffirepro_26_clk_src_types ,
2014-04-25 22:45:24 +09:00
. get = & saffirepro_both_clk_src_get ,
} ;
2015-10-11 08:10:55 +02:00
const struct snd_bebob_spec saffirepro_26_spec = {
2014-04-25 22:45:24 +09:00
. clock = & saffirepro_26_clk_spec ,
. rate = & saffirepro_both_rate_spec ,
. meter = NULL
} ;
/* Saffire Pro 10 I/O */
2015-10-11 08:10:55 +02:00
static const struct snd_bebob_clock_spec saffirepro_10_clk_spec = {
2015-06-14 12:49:29 +09:00
. num = ARRAY_SIZE ( saffirepro_10_clk_src_types ) ,
. types = saffirepro_10_clk_src_types ,
2014-04-25 22:45:24 +09:00
. get = & saffirepro_both_clk_src_get ,
} ;
2015-10-11 08:10:55 +02:00
const struct snd_bebob_spec saffirepro_10_spec = {
2014-04-25 22:45:24 +09:00
. clock = & saffirepro_10_clk_spec ,
. rate = & saffirepro_both_rate_spec ,
. meter = NULL
} ;
2015-10-11 08:10:55 +02:00
static const struct snd_bebob_rate_spec saffire_both_rate_spec = {
2014-04-25 22:45:24 +09:00
. get = & snd_bebob_stream_get_rate ,
. set = & snd_bebob_stream_set_rate ,
} ;
2015-10-11 08:10:55 +02:00
static const struct snd_bebob_clock_spec saffire_both_clk_spec = {
2015-06-14 12:49:29 +09:00
. num = ARRAY_SIZE ( saffire_both_clk_src_types ) ,
. types = saffire_both_clk_src_types ,
2014-04-25 22:45:24 +09:00
. get = & saffire_both_clk_src_get ,
} ;
/* Saffire LE */
2015-10-11 08:10:55 +02:00
static const struct snd_bebob_meter_spec saffire_le_meter_spec = {
2014-04-25 22:45:24 +09:00
. num = ARRAY_SIZE ( saffire_le_meter_labels ) ,
. labels = saffire_le_meter_labels ,
. get = & saffire_meter_get ,
} ;
2015-10-11 08:10:55 +02:00
const struct snd_bebob_spec saffire_le_spec = {
2014-04-25 22:45:24 +09:00
. clock = & saffire_both_clk_spec ,
. rate = & saffire_both_rate_spec ,
. meter = & saffire_le_meter_spec
} ;
/* Saffire */
2015-10-11 08:10:55 +02:00
static const struct snd_bebob_meter_spec saffire_meter_spec = {
2014-04-25 22:45:24 +09:00
. num = ARRAY_SIZE ( saffire_meter_labels ) ,
. labels = saffire_meter_labels ,
. get = & saffire_meter_get ,
} ;
2015-10-11 08:10:55 +02:00
const struct snd_bebob_spec saffire_spec = {
2014-04-25 22:45:24 +09:00
. clock = & saffire_both_clk_spec ,
. rate = & saffire_both_rate_spec ,
. meter = & saffire_meter_spec
} ;