Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
33a8415f
Commit
33a8415f
authored
Dec 02, 2012
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/wm0010' into asoc-next
parents
fa3800dd
5d910966
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
248 additions
and
171 deletions
+248
-171
sound/soc/codecs/wm0010.c
sound/soc/codecs/wm0010.c
+248
-171
No files found.
sound/soc/codecs/wm0010.c
View file @
33a8415f
...
...
@@ -31,6 +31,9 @@
#define DEVICE_ID_WM0010 10
/* We only support v1 of the .dfw INFO record */
#define INFO_VERSION 1
enum
dfw_cmd
{
DFW_CMD_FUSE
=
0x01
,
DFW_CMD_CODE_HDR
,
...
...
@@ -46,6 +49,13 @@ struct dfw_binrec {
uint8_t
data
[
0
];
}
__packed
;
struct
dfw_inforec
{
u8
info_version
;
u8
tool_major_version
;
u8
tool_minor_version
;
u8
dsp_target
;
};
struct
dfw_pllrec
{
u8
command
;
u32
length
:
24
;
...
...
@@ -97,7 +107,6 @@ struct wm0010_priv {
enum
wm0010_state
state
;
bool
boot_failed
;
int
boot_done
;
bool
ready
;
bool
pll_running
;
int
max_spi_freq
;
...
...
@@ -234,7 +243,7 @@ static void wm0010_boot_xfer_complete(void *data)
break
;
case
0x55555555
:
if
(
wm0010
->
boot_done
==
0
)
if
(
wm0010
->
state
<
WM0010_STAGE2
)
break
;
dev_err
(
codec
->
dev
,
"%d: ROM bootloader running in stage 2
\n
"
,
i
);
...
...
@@ -321,7 +330,6 @@ static void wm0010_boot_xfer_complete(void *data)
break
;
}
wm0010
->
boot_done
++
;
if
(
xfer
->
done
)
complete
(
xfer
->
done
);
}
...
...
@@ -334,94 +342,198 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
data_out
[
i
]
=
cpu_to_be64
(
le64_to_cpu
(
data_in
[
i
]));
}
static
int
wm0010_
boot
(
struct
snd_soc_codec
*
codec
)
static
int
wm0010_
firmware_load
(
char
*
name
,
struct
snd_soc_codec
*
codec
)
{
struct
spi_device
*
spi
=
to_spi_device
(
codec
->
dev
);
struct
wm0010_priv
*
wm0010
=
snd_soc_codec_get_drvdata
(
codec
);
unsigned
long
flags
;
struct
list_head
xfer_list
;
struct
wm0010_boot_xfer
*
xfer
;
int
ret
;
struct
completion
done
;
const
struct
firmware
*
fw
;
const
struct
dfw_binrec
*
rec
;
struct
spi_message
m
;
struct
spi_transfer
t
;
struct
dfw_pllrec
pll_rec
;
u32
*
img
,
*
p
;
u64
*
img_swap
;
u8
*
out
;
const
struct
dfw_inforec
*
inforec
;
u64
*
img
;
u8
*
out
,
dsp
;
u32
len
,
offset
;
int
i
;
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
if
(
wm0010
->
state
!=
WM0010_POWER_OFF
)
dev_warn
(
wm0010
->
dev
,
"DSP already powered up!
\n
"
);
spin_unlock_irqrestore
(
&
wm0010
->
irq_lock
,
flags
);
INIT_LIST_HEAD
(
&
xfer_list
);
if
(
wm0010
->
sysclk
>
26000000
)
{
dev_err
(
codec
->
dev
,
"Max DSP clock frequency is 26MHz
\n
"
);
ret
=
-
ECANCELED
;
goto
err
;
ret
=
request_firmware
(
&
fw
,
name
,
codec
->
dev
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to request application: %d
\n
"
,
ret
);
return
ret
;
}
INIT_LIST_HEAD
(
&
xfer_list
);
rec
=
(
const
struct
dfw_binrec
*
)
fw
->
data
;
inforec
=
(
const
struct
dfw_inforec
*
)
rec
->
data
;
offset
=
0
;
dsp
=
inforec
->
dsp_target
;
wm0010
->
boot_failed
=
false
;
BUG_ON
(
!
list_empty
(
&
xfer_list
));
init_completion
(
&
done
);
mutex_lock
(
&
wm0010
->
lock
);
wm0010
->
pll_running
=
false
;
/* First record should be INFO */
if
(
rec
->
command
!=
DFW_CMD_INFO
)
{
dev_err
(
codec
->
dev
,
"First record not INFO
\r\n
"
);
ret
=
-
EINVAL
;
goto
abort
;
}
dev_dbg
(
codec
->
dev
,
"max_spi_freq: %d
\n
"
,
wm0010
->
max_spi_freq
);
if
(
inforec
->
info_version
!=
INFO_VERSION
)
{
dev_err
(
codec
->
dev
,
"Unsupported version (%02d) of INFO record
\r\n
"
,
inforec
->
info_version
);
ret
=
-
EINVAL
;
goto
abort
;
}
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
wm0010
->
core_supplies
),
wm0010
->
core_supplies
);
if
(
ret
!=
0
)
{
dev_err
(
&
spi
->
dev
,
"Failed to enable core supplies: %d
\n
"
,
ret
);
mutex_unlock
(
&
wm0010
->
lock
);
goto
err
;
dev_dbg
(
codec
->
dev
,
"Version v%02d INFO record found
\r\n
"
,
inforec
->
info_version
);
/* Check it's a DSP file */
if
(
dsp
!=
DEVICE_ID_WM0010
)
{
dev_err
(
codec
->
dev
,
"Not a WM0010 firmware file.
\r\n
"
);
ret
=
-
EINVAL
;
goto
abort
;
}
ret
=
regulator_enable
(
wm0010
->
dbvdd
);
/* Skip the info record as we don't need to send it */
offset
+=
((
rec
->
length
)
+
8
);
rec
=
(
void
*
)
&
rec
->
data
[
rec
->
length
];
while
(
offset
<
fw
->
size
)
{
dev_dbg
(
codec
->
dev
,
"Packet: command %d, data length = 0x%x
\r\n
"
,
rec
->
command
,
rec
->
length
);
len
=
rec
->
length
+
8
;
out
=
kzalloc
(
len
,
GFP_KERNEL
);
if
(
!
out
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate RX buffer
\n
"
);
ret
=
-
ENOMEM
;
goto
abort1
;
}
img
=
kzalloc
(
len
,
GFP_KERNEL
);
if
(
!
img
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate image buffer
\n
"
);
ret
=
-
ENOMEM
;
goto
abort1
;
}
byte_swap_64
((
u64
*
)
&
rec
->
command
,
img
,
len
);
xfer
=
kzalloc
(
sizeof
(
*
xfer
),
GFP_KERNEL
);
if
(
!
xfer
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate xfer
\n
"
);
ret
=
-
ENOMEM
;
goto
abort1
;
}
xfer
->
codec
=
codec
;
list_add_tail
(
&
xfer
->
list
,
&
xfer_list
);
spi_message_init
(
&
xfer
->
m
);
xfer
->
m
.
complete
=
wm0010_boot_xfer_complete
;
xfer
->
m
.
context
=
xfer
;
xfer
->
t
.
tx_buf
=
img
;
xfer
->
t
.
rx_buf
=
out
;
xfer
->
t
.
len
=
len
;
xfer
->
t
.
bits_per_word
=
8
;
if
(
!
wm0010
->
pll_running
)
{
xfer
->
t
.
speed_hz
=
wm0010
->
sysclk
/
6
;
}
else
{
xfer
->
t
.
speed_hz
=
wm0010
->
max_spi_freq
;
if
(
wm0010
->
board_max_spi_speed
&&
(
wm0010
->
board_max_spi_speed
<
wm0010
->
max_spi_freq
))
xfer
->
t
.
speed_hz
=
wm0010
->
board_max_spi_speed
;
}
/* Store max usable spi frequency for later use */
wm0010
->
max_spi_freq
=
xfer
->
t
.
speed_hz
;
spi_message_add_tail
(
&
xfer
->
t
,
&
xfer
->
m
);
offset
+=
((
rec
->
length
)
+
8
);
rec
=
(
void
*
)
&
rec
->
data
[
rec
->
length
];
if
(
offset
>=
fw
->
size
)
{
dev_dbg
(
codec
->
dev
,
"All transfers scheduled
\n
"
);
xfer
->
done
=
&
done
;
}
ret
=
spi_async
(
spi
,
&
xfer
->
m
);
if
(
ret
!=
0
)
{
dev_err
(
&
spi
->
dev
,
"Failed to enable DBVDD
: %d
\n
"
,
ret
);
goto
err_core
;
dev_err
(
codec
->
dev
,
"Write failed
: %d
\n
"
,
ret
);
goto
abort1
;
}
/* Release reset */
gpio_set_value_cansleep
(
wm0010
->
gpio_reset
,
!
wm0010
->
gpio_reset_value
);
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
wm0010
->
state
=
WM0010_OUT_OF_RESET
;
spin_unlock_irqrestore
(
&
wm0010
->
irq_lock
,
flags
);
if
(
wm0010
->
boot_failed
)
{
dev_dbg
(
codec
->
dev
,
"Boot fail!
\n
"
);
ret
=
-
EINVAL
;
goto
abort1
;
}
}
wait_for_completion
(
&
done
);
ret
=
0
;
abort1:
while
(
!
list_empty
(
&
xfer_list
))
{
xfer
=
list_first_entry
(
&
xfer_list
,
struct
wm0010_boot_xfer
,
list
);
kfree
(
xfer
->
t
.
rx_buf
);
kfree
(
xfer
->
t
.
tx_buf
);
list_del
(
&
xfer
->
list
);
kfree
(
xfer
);
}
abort:
release_firmware
(
fw
);
return
ret
;
}
static
int
wm0010_stage2_load
(
struct
snd_soc_codec
*
codec
)
{
struct
spi_device
*
spi
=
to_spi_device
(
codec
->
dev
);
struct
wm0010_priv
*
wm0010
=
snd_soc_codec_get_drvdata
(
codec
);
const
struct
firmware
*
fw
;
struct
spi_message
m
;
struct
spi_transfer
t
;
u32
*
img
;
u8
*
out
;
int
i
;
int
ret
=
0
;
/* First the bootloader */
ret
=
request_firmware
(
&
fw
,
"wm0010_stage2.bin"
,
codec
->
dev
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to request stage2 loader: %d
\n
"
,
ret
);
goto
abor
t
;
return
re
t
;
}
if
(
!
wait_for_completion_timeout
(
&
wm0010
->
boot_completion
,
msecs_to_jiffies
(
10
)))
dev_err
(
codec
->
dev
,
"Failed to get interrupt from DSP
\n
"
);
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
wm0010
->
state
=
WM0010_BOOTROM
;
spin_unlock_irqrestore
(
&
wm0010
->
irq_lock
,
flags
);
dev_dbg
(
codec
->
dev
,
"Downloading %zu byte stage 2 loader
\n
"
,
fw
->
size
);
/* Copy to local buffer first as vmalloc causes problems for dma */
img
=
kzalloc
(
fw
->
size
,
GFP_KERNEL
);
if
(
!
img
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate image buffer
\n
"
);
goto
abort
;
ret
=
-
ENOMEM
;
goto
abort2
;
}
out
=
kzalloc
(
fw
->
size
,
GFP_KERNEL
);
if
(
!
out
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate output buffer
\n
"
);
goto
abort
;
ret
=
-
ENOMEM
;
goto
abort1
;
}
memcpy
(
img
,
&
fw
->
data
[
0
],
fw
->
size
);
...
...
@@ -447,20 +559,97 @@ static int wm0010_boot(struct snd_soc_codec *codec)
/* Look for errors from the boot ROM */
for
(
i
=
0
;
i
<
fw
->
size
;
i
++
)
{
if
(
out
[
i
]
!=
0x55
)
{
ret
=
-
EBUSY
;
dev_err
(
codec
->
dev
,
"Boot ROM error: %x in %d
\n
"
,
out
[
i
],
i
);
wm0010_mark_boot_failure
(
wm0010
);
ret
=
-
EBUSY
;
goto
abort
;
}
}
release_firmware
(
fw
);
kfree
(
img
);
abort:
kfree
(
out
);
abort1:
kfree
(
img
);
abort2:
release_firmware
(
fw
);
return
ret
;
}
static
int
wm0010_boot
(
struct
snd_soc_codec
*
codec
)
{
struct
spi_device
*
spi
=
to_spi_device
(
codec
->
dev
);
struct
wm0010_priv
*
wm0010
=
snd_soc_codec_get_drvdata
(
codec
);
unsigned
long
flags
;
int
ret
;
const
struct
firmware
*
fw
;
struct
spi_message
m
;
struct
spi_transfer
t
;
struct
dfw_pllrec
pll_rec
;
u32
*
p
,
len
;
u64
*
img_swap
;
u8
*
out
;
int
i
;
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
if
(
wm0010
->
state
!=
WM0010_POWER_OFF
)
dev_warn
(
wm0010
->
dev
,
"DSP already powered up!
\n
"
);
spin_unlock_irqrestore
(
&
wm0010
->
irq_lock
,
flags
);
if
(
wm0010
->
sysclk
>
26000000
)
{
dev_err
(
codec
->
dev
,
"Max DSP clock frequency is 26MHz
\n
"
);
ret
=
-
ECANCELED
;
goto
err
;
}
mutex_lock
(
&
wm0010
->
lock
);
wm0010
->
pll_running
=
false
;
dev_dbg
(
codec
->
dev
,
"max_spi_freq: %d
\n
"
,
wm0010
->
max_spi_freq
);
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
wm0010
->
core_supplies
),
wm0010
->
core_supplies
);
if
(
ret
!=
0
)
{
dev_err
(
&
spi
->
dev
,
"Failed to enable core supplies: %d
\n
"
,
ret
);
mutex_unlock
(
&
wm0010
->
lock
);
goto
err
;
}
ret
=
regulator_enable
(
wm0010
->
dbvdd
);
if
(
ret
!=
0
)
{
dev_err
(
&
spi
->
dev
,
"Failed to enable DBVDD: %d
\n
"
,
ret
);
goto
err_core
;
}
/* Release reset */
gpio_set_value_cansleep
(
wm0010
->
gpio_reset
,
!
wm0010
->
gpio_reset_value
);
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
wm0010
->
state
=
WM0010_OUT_OF_RESET
;
spin_unlock_irqrestore
(
&
wm0010
->
irq_lock
,
flags
);
/* First the bootloader */
ret
=
request_firmware
(
&
fw
,
"wm0010_stage2.bin"
,
codec
->
dev
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to request stage2 loader: %d
\n
"
,
ret
);
goto
abort
;
}
if
(
!
wait_for_completion_timeout
(
&
wm0010
->
boot_completion
,
msecs_to_jiffies
(
20
)))
dev_err
(
codec
->
dev
,
"Failed to get interrupt from DSP
\n
"
);
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
wm0010
->
state
=
WM0010_BOOTROM
;
spin_unlock_irqrestore
(
&
wm0010
->
irq_lock
,
flags
);
ret
=
wm0010_stage2_load
(
codec
);
if
(
ret
)
goto
abort
;
if
(
!
wait_for_completion_timeout
(
&
wm0010
->
boot_completion
,
msecs_to_jiffies
(
1
0
)))
msecs_to_jiffies
(
2
0
)))
dev_err
(
codec
->
dev
,
"Failed to get interrupt from DSP loader.
\n
"
);
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
...
...
@@ -535,110 +724,10 @@ static int wm0010_boot(struct snd_soc_codec *codec)
}
else
dev_dbg
(
codec
->
dev
,
"Not enabling DSP PLL."
);
ret
=
request_firmware
(
&
fw
,
"wm0010.dfw"
,
codec
->
dev
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to request application: %d
\n
"
,
ret
);
goto
abort
;
}
rec
=
(
const
struct
dfw_binrec
*
)
fw
->
data
;
offset
=
0
;
wm0010
->
boot_done
=
0
;
wm0010
->
boot_failed
=
false
;
BUG_ON
(
!
list_empty
(
&
xfer_list
));
init_completion
(
&
done
);
/* First record should be INFO */
if
(
rec
->
command
!=
DFW_CMD_INFO
)
{
dev_err
(
codec
->
dev
,
"First record not INFO
\r\n
"
);
goto
abort
;
}
/* Check it's a 0010 file */
if
(
rec
->
data
[
0
]
!=
DEVICE_ID_WM0010
)
{
dev_err
(
codec
->
dev
,
"Not a WM0010 firmware file.
\r\n
"
);
goto
abort
;
}
/* Skip the info record as we don't need to send it */
offset
+=
((
rec
->
length
)
+
8
);
rec
=
(
void
*
)
&
rec
->
data
[
rec
->
length
];
while
(
offset
<
fw
->
size
)
{
dev_dbg
(
codec
->
dev
,
"Packet: command %d, data length = 0x%x
\r\n
"
,
rec
->
command
,
rec
->
length
);
len
=
rec
->
length
+
8
;
out
=
kzalloc
(
len
,
GFP_KERNEL
);
if
(
!
out
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate RX buffer
\n
"
);
goto
abort
;
}
img_swap
=
kzalloc
(
len
,
GFP_KERNEL
);
if
(
!
img_swap
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate image buffer
\n
"
);
goto
abort
;
}
/* We need to re-order for 0010 */
byte_swap_64
((
u64
*
)
&
rec
->
command
,
img_swap
,
len
);
ret
=
wm0010_firmware_load
(
"wm0010.dfw"
,
codec
);
xfer
=
kzalloc
(
sizeof
(
*
xfer
),
GFP_KERNEL
);
if
(
!
xfer
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate xfer
\n
"
);
if
(
ret
!=
0
)
goto
abort
;
}
xfer
->
codec
=
codec
;
list_add_tail
(
&
xfer
->
list
,
&
xfer_list
);
spi_message_init
(
&
xfer
->
m
);
xfer
->
m
.
complete
=
wm0010_boot_xfer_complete
;
xfer
->
m
.
context
=
xfer
;
xfer
->
t
.
tx_buf
=
img_swap
;
xfer
->
t
.
rx_buf
=
out
;
xfer
->
t
.
len
=
len
;
xfer
->
t
.
bits_per_word
=
8
;
if
(
!
wm0010
->
pll_running
)
{
xfer
->
t
.
speed_hz
=
wm0010
->
sysclk
/
6
;
}
else
{
xfer
->
t
.
speed_hz
=
wm0010
->
max_spi_freq
;
if
(
wm0010
->
board_max_spi_speed
&&
(
wm0010
->
board_max_spi_speed
<
wm0010
->
max_spi_freq
))
xfer
->
t
.
speed_hz
=
wm0010
->
board_max_spi_speed
;
}
/* Store max usable spi frequency for later use */
wm0010
->
max_spi_freq
=
xfer
->
t
.
speed_hz
;
spi_message_add_tail
(
&
xfer
->
t
,
&
xfer
->
m
);
offset
+=
((
rec
->
length
)
+
8
);
rec
=
(
void
*
)
&
rec
->
data
[
rec
->
length
];
if
(
offset
>=
fw
->
size
)
{
dev_dbg
(
codec
->
dev
,
"All transfers scheduled
\n
"
);
xfer
->
done
=
&
done
;
}
ret
=
spi_async
(
spi
,
&
xfer
->
m
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Write failed: %d
\n
"
,
ret
);
goto
abort
;
}
if
(
wm0010
->
boot_failed
)
goto
abort
;
}
wait_for_completion
(
&
done
);
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
wm0010
->
state
=
WM0010_FIRMWARE
;
...
...
@@ -646,17 +735,6 @@ static int wm0010_boot(struct snd_soc_codec *codec)
mutex_unlock
(
&
wm0010
->
lock
);
release_firmware
(
fw
);
while
(
!
list_empty
(
&
xfer_list
))
{
xfer
=
list_first_entry
(
&
xfer_list
,
struct
wm0010_boot_xfer
,
list
);
kfree
(
xfer
->
t
.
rx_buf
);
kfree
(
xfer
->
t
.
tx_buf
);
list_del
(
&
xfer
->
list
);
kfree
(
xfer
);
}
return
0
;
abort:
...
...
@@ -784,7 +862,6 @@ static irqreturn_t wm0010_irq(int irq, void *data)
struct
wm0010_priv
*
wm0010
=
data
;
switch
(
wm0010
->
state
)
{
case
WM0010_POWER_OFF
:
case
WM0010_OUT_OF_RESET
:
case
WM0010_BOOTROM
:
case
WM0010_STAGE2
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment