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
bba1594d
Commit
bba1594d
authored
Mar 24, 2012
by
Russell King
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'mmci' into amba
parents
9e5ed094
7437cfa5
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
151 additions
and
73 deletions
+151
-73
arch/arm/mach-ux500/board-mop500-sdi.c
arch/arm/mach-ux500/board-mop500-sdi.c
+8
-13
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.c
+121
-45
drivers/mmc/host/mmci.h
drivers/mmc/host/mmci.h
+3
-12
include/linux/amba/mmci.h
include/linux/amba/mmci.h
+19
-3
No files found.
arch/arm/mach-ux500/board-mop500-sdi.c
View file @
bba1594d
...
...
@@ -31,21 +31,13 @@
* SDI 0 (MicroSD slot)
*/
/* MMCIPOWER bits */
#define MCI_DATA2DIREN (1 << 2)
#define MCI_CMDDIREN (1 << 3)
#define MCI_DATA0DIREN (1 << 4)
#define MCI_DATA31DIREN (1 << 5)
#define MCI_FBCLKEN (1 << 7)
/* GPIO pins used by the sdi0 level shifter */
static
int
sdi0_en
=
-
1
;
static
int
sdi0_vsel
=
-
1
;
static
u32
mop500_sdi0_vdd_handler
(
struct
device
*
dev
,
unsigned
int
vdd
,
unsigned
char
power_mode
)
static
int
mop500_sdi0_ios_handler
(
struct
device
*
dev
,
struct
mmc_ios
*
ios
)
{
switch
(
power_mode
)
{
switch
(
ios
->
power_mode
)
{
case
MMC_POWER_UP
:
case
MMC_POWER_ON
:
/*
...
...
@@ -65,8 +57,7 @@ static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd,
break
;
}
return
MCI_FBCLKEN
|
MCI_CMDDIREN
|
MCI_DATA0DIREN
|
MCI_DATA2DIREN
|
MCI_DATA31DIREN
;
return
0
;
}
#ifdef CONFIG_STE_DMA40
...
...
@@ -90,13 +81,17 @@ static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = {
#endif
static
struct
mmci_platform_data
mop500_sdi0_data
=
{
.
vdd_handler
=
mop500_sdi0_vdd
_handler
,
.
ios_handler
=
mop500_sdi0_ios
_handler
,
.
ocr_mask
=
MMC_VDD_29_30
,
.
f_max
=
50000000
,
.
capabilities
=
MMC_CAP_4_BIT_DATA
|
MMC_CAP_SD_HIGHSPEED
|
MMC_CAP_MMC_HIGHSPEED
,
.
gpio_wp
=
-
1
,
.
sigdir
=
MCI_ST_FBCLKEN
|
MCI_ST_CMDDIREN
|
MCI_ST_DATA0DIREN
|
MCI_ST_DATA2DIREN
,
#ifdef CONFIG_STE_DMA40
.
dma_filter
=
stedma40_filter
,
.
dma_rx_param
=
&
mop500_sdi0_dma_cfg_rx
,
...
...
drivers/mmc/host/mmci.c
View file @
bba1594d
...
...
@@ -53,6 +53,8 @@ static unsigned int fmax = 515633;
* @sdio: variant supports SDIO
* @st_clkdiv: true if using a ST-specific clock divider algorithm
* @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
* @pwrreg_powerup: power up value for MMCIPOWER register
* @signal_direction: input/out direction of bus signals can be indicated
*/
struct
variant_data
{
unsigned
int
clkreg
;
...
...
@@ -63,18 +65,22 @@ struct variant_data {
bool
sdio
;
bool
st_clkdiv
;
bool
blksz_datactrl16
;
u32
pwrreg_powerup
;
bool
signal_direction
;
};
static
struct
variant_data
variant_arm
=
{
.
fifosize
=
16
*
4
,
.
fifohalfsize
=
8
*
4
,
.
datalength_bits
=
16
,
.
pwrreg_powerup
=
MCI_PWR_UP
,
};
static
struct
variant_data
variant_arm_extended_fifo
=
{
.
fifosize
=
128
*
4
,
.
fifohalfsize
=
64
*
4
,
.
datalength_bits
=
16
,
.
pwrreg_powerup
=
MCI_PWR_UP
,
};
static
struct
variant_data
variant_u300
=
{
...
...
@@ -83,6 +89,8 @@ static struct variant_data variant_u300 = {
.
clkreg_enable
=
MCI_ST_U300_HWFCEN
,
.
datalength_bits
=
16
,
.
sdio
=
true
,
.
pwrreg_powerup
=
MCI_PWR_ON
,
.
signal_direction
=
true
,
};
static
struct
variant_data
variant_ux500
=
{
...
...
@@ -93,6 +101,8 @@ static struct variant_data variant_ux500 = {
.
datalength_bits
=
24
,
.
sdio
=
true
,
.
st_clkdiv
=
true
,
.
pwrreg_powerup
=
MCI_PWR_ON
,
.
signal_direction
=
true
,
};
static
struct
variant_data
variant_ux500v2
=
{
...
...
@@ -104,8 +114,32 @@ static struct variant_data variant_ux500v2 = {
.
sdio
=
true
,
.
st_clkdiv
=
true
,
.
blksz_datactrl16
=
true
,
.
pwrreg_powerup
=
MCI_PWR_ON
,
.
signal_direction
=
true
,
};
/*
* This must be called with host->lock held
*/
static
void
mmci_write_clkreg
(
struct
mmci_host
*
host
,
u32
clk
)
{
if
(
host
->
clk_reg
!=
clk
)
{
host
->
clk_reg
=
clk
;
writel
(
clk
,
host
->
base
+
MMCICLOCK
);
}
}
/*
* This must be called with host->lock held
*/
static
void
mmci_write_pwrreg
(
struct
mmci_host
*
host
,
u32
pwr
)
{
if
(
host
->
pwr_reg
!=
pwr
)
{
host
->
pwr_reg
=
pwr
;
writel
(
pwr
,
host
->
base
+
MMCIPOWER
);
}
}
/*
* This must be called with host->lock held
*/
...
...
@@ -153,7 +187,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
if
(
host
->
mmc
->
ios
.
bus_width
==
MMC_BUS_WIDTH_8
)
clk
|=
MCI_ST_8BIT_BUS
;
writel
(
clk
,
host
->
base
+
MMCICLOCK
);
mmci_write_clkreg
(
host
,
clk
);
}
static
void
...
...
@@ -166,14 +200,10 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
host
->
mrq
=
NULL
;
host
->
cmd
=
NULL
;
/*
* Need to drop the host lock here; mmc_request_done may call
* back into the driver...
*/
spin_unlock
(
&
host
->
lock
);
pm_runtime_put
(
mmc_dev
(
host
->
mmc
));
mmc_request_done
(
host
->
mmc
,
mrq
);
spin_lock
(
&
host
->
lock
);
pm_runtime_mark_last_busy
(
mmc_dev
(
host
->
mmc
));
pm_runtime_put_autosuspend
(
mmc_dev
(
host
->
mmc
));
}
static
void
mmci_set_mask1
(
struct
mmci_host
*
host
,
unsigned
int
mask
)
...
...
@@ -607,6 +637,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
if
(
data
->
flags
&
MMC_DATA_READ
)
datactrl
|=
MCI_DPSM_DIRECTION
;
/* The ST Micro variants has a special bit to enable SDIO */
if
(
variant
->
sdio
&&
host
->
mmc
->
card
)
if
(
mmc_card_sdio
(
host
->
mmc
->
card
))
datactrl
|=
MCI_ST_DPSM_SDIOEN
;
/*
* Attempt to use DMA operation mode, if this
* should fail, fall back to PIO mode
...
...
@@ -635,11 +670,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
irqmask
=
MCI_TXFIFOHALFEMPTYMASK
;
}
/* The ST Micro variants has a special bit to enable SDIO */
if
(
variant
->
sdio
&&
host
->
mmc
->
card
)
if
(
mmc_card_sdio
(
host
->
mmc
->
card
))
datactrl
|=
MCI_ST_DPSM_SDIOEN
;
writel
(
datactrl
,
base
+
MMCIDATACTRL
);
writel
(
readl
(
base
+
MMCIMASK0
)
&
~
MCI_DATAENDMASK
,
base
+
MMCIMASK0
);
mmci_set_mask1
(
host
,
irqmask
);
...
...
@@ -786,7 +816,24 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
if
(
count
<=
0
)
break
;
/*
* SDIO especially may want to send something that is
* not divisible by 4 (as opposed to card sectors
* etc). Therefore make sure to always read the last bytes
* while only doing full 32-bit reads towards the FIFO.
*/
if
(
unlikely
(
count
&
0x3
))
{
if
(
count
<
4
)
{
unsigned
char
buf
[
4
];
readsl
(
base
+
MMCIFIFO
,
buf
,
1
);
memcpy
(
ptr
,
buf
,
count
);
}
else
{
readsl
(
base
+
MMCIFIFO
,
ptr
,
count
>>
2
);
count
&=
~
0x3
;
}
}
else
{
readsl
(
base
+
MMCIFIFO
,
ptr
,
count
>>
2
);
}
ptr
+=
count
;
remain
-=
count
;
...
...
@@ -821,14 +868,13 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
*/
if
(
variant
->
sdio
&&
mmc_card_sdio
(
host
->
mmc
->
card
))
{
u32
clk
;
if
(
count
<
8
)
writel
(
readl
(
host
->
base
+
MMCICLOCK
)
&
~
variant
->
clkreg_enable
,
host
->
base
+
MMCICLOCK
);
clk
=
host
->
clk_reg
&
~
variant
->
clkreg_enable
;
else
writel
(
readl
(
host
->
base
+
MMCICLOCK
)
|
variant
->
clkreg_enable
,
host
->
base
+
MMCICLOCK
);
clk
=
host
->
clk_reg
|
variant
->
clkreg_enable
;
mmci_write_clkreg
(
host
,
clk
);
}
/*
...
...
@@ -1015,10 +1061,17 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
static
void
mmci_set_ios
(
struct
mmc_host
*
mmc
,
struct
mmc_ios
*
ios
)
{
struct
mmci_host
*
host
=
mmc_priv
(
mmc
);
struct
variant_data
*
variant
=
host
->
variant
;
u32
pwr
=
0
;
unsigned
long
flags
;
int
ret
;
pm_runtime_get_sync
(
mmc_dev
(
mmc
));
if
(
host
->
plat
->
ios_handler
&&
host
->
plat
->
ios_handler
(
mmc_dev
(
mmc
),
ios
))
dev_err
(
mmc_dev
(
mmc
),
"platform ios_handler failed
\n
"
);
switch
(
ios
->
power_mode
)
{
case
MMC_POWER_OFF
:
if
(
host
->
vcc
)
...
...
@@ -1035,22 +1088,38 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
* power should be rare so we print an error
* and return here.
*/
return
;
goto
out
;
}
}
if
(
host
->
plat
->
vdd_handler
)
pwr
|=
host
->
plat
->
vdd_handler
(
mmc_dev
(
mmc
),
ios
->
vdd
,
ios
->
power_mode
);
/* The ST version does not have this, fall through to POWER_ON */
if
(
host
->
hw_designer
!=
AMBA_VENDOR_ST
)
{
pwr
|=
MCI_PWR_UP
;
/*
* The ST Micro variant doesn't have the PL180s MCI_PWR_UP
* and instead uses MCI_PWR_ON so apply whatever value is
* configured in the variant data.
*/
pwr
|=
variant
->
pwrreg_powerup
;
break
;
}
case
MMC_POWER_ON
:
pwr
|=
MCI_PWR_ON
;
break
;
}
if
(
variant
->
signal_direction
&&
ios
->
power_mode
!=
MMC_POWER_OFF
)
{
/*
* The ST Micro variant has some additional bits
* indicating signal direction for the signals in
* the SD/MMC bus and feedback-clock usage.
*/
pwr
|=
host
->
plat
->
sigdir
;
if
(
ios
->
bus_width
==
MMC_BUS_WIDTH_4
)
pwr
&=
~
MCI_ST_DATA74DIREN
;
else
if
(
ios
->
bus_width
==
MMC_BUS_WIDTH_1
)
pwr
&=
(
~
MCI_ST_DATA74DIREN
&
~
MCI_ST_DATA31DIREN
&
~
MCI_ST_DATA2DIREN
);
}
if
(
ios
->
bus_mode
==
MMC_BUSMODE_OPENDRAIN
)
{
if
(
host
->
hw_designer
!=
AMBA_VENDOR_ST
)
pwr
|=
MCI_ROD
;
...
...
@@ -1066,13 +1135,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
mmci_set_clkreg
(
host
,
ios
->
clock
);
if
(
host
->
pwr
!=
pwr
)
{
host
->
pwr
=
pwr
;
writel
(
pwr
,
host
->
base
+
MMCIPOWER
);
}
mmci_write_pwrreg
(
host
,
pwr
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
out:
pm_runtime_mark_last_busy
(
mmc_dev
(
mmc
));
pm_runtime_put_autosuspend
(
mmc_dev
(
mmc
));
}
static
int
mmci_get_ro
(
struct
mmc_host
*
mmc
)
...
...
@@ -1345,6 +1414,8 @@ static int __devinit mmci_probe(struct amba_device *dev,
mmci_dma_setup
(
host
);
pm_runtime_set_autosuspend_delay
(
&
dev
->
dev
,
50
);
pm_runtime_use_autosuspend
(
&
dev
->
dev
);
pm_runtime_put
(
&
dev
->
dev
);
mmc_add_host
(
mmc
);
...
...
@@ -1429,43 +1500,49 @@ static int __devexit mmci_remove(struct amba_device *dev)
return
0
;
}
#ifdef CONFIG_
PM
static
int
mmci_suspend
(
struct
amba_device
*
dev
,
pm_message_t
state
)
#ifdef CONFIG_
SUSPEND
static
int
mmci_suspend
(
struct
device
*
dev
)
{
struct
mmc_host
*
mmc
=
amba_get_drvdata
(
dev
);
struct
amba_device
*
adev
=
to_amba_device
(
dev
);
struct
mmc_host
*
mmc
=
amba_get_drvdata
(
adev
);
int
ret
=
0
;
if
(
mmc
)
{
struct
mmci_host
*
host
=
mmc_priv
(
mmc
);
ret
=
mmc_suspend_host
(
mmc
);
if
(
ret
==
0
)
if
(
ret
==
0
)
{
pm_runtime_get_sync
(
dev
);
writel
(
0
,
host
->
base
+
MMCIMASK0
);
}
}
return
ret
;
}
static
int
mmci_resume
(
struct
amba_
device
*
dev
)
static
int
mmci_resume
(
struct
device
*
dev
)
{
struct
mmc_host
*
mmc
=
amba_get_drvdata
(
dev
);
struct
amba_device
*
adev
=
to_amba_device
(
dev
);
struct
mmc_host
*
mmc
=
amba_get_drvdata
(
adev
);
int
ret
=
0
;
if
(
mmc
)
{
struct
mmci_host
*
host
=
mmc_priv
(
mmc
);
writel
(
MCI_IRQENABLE
,
host
->
base
+
MMCIMASK0
);
pm_runtime_put
(
dev
);
ret
=
mmc_resume_host
(
mmc
);
}
return
ret
;
}
#else
#define mmci_suspend NULL
#define mmci_resume NULL
#endif
static
const
struct
dev_pm_ops
mmci_dev_pm_ops
=
{
SET_SYSTEM_SLEEP_PM_OPS
(
mmci_suspend
,
mmci_resume
)
};
static
struct
amba_id
mmci_ids
[]
=
{
{
.
id
=
0x00041180
,
...
...
@@ -1511,11 +1588,10 @@ MODULE_DEVICE_TABLE(amba, mmci_ids);
static
struct
amba_driver
mmci_driver
=
{
.
drv
=
{
.
name
=
DRIVER_NAME
,
.
pm
=
&
mmci_dev_pm_ops
,
},
.
probe
=
mmci_probe
,
.
remove
=
__devexit_p
(
mmci_remove
),
.
suspend
=
mmci_suspend
,
.
resume
=
mmci_resume
,
.
id_table
=
mmci_ids
,
};
...
...
drivers/mmc/host/mmci.h
View file @
bba1594d
...
...
@@ -13,16 +13,6 @@
#define MCI_PWR_ON 0x03
#define MCI_OD (1 << 6)
#define MCI_ROD (1 << 7)
/*
* The ST Micro version does not have ROD and reuse the voltage registers
* for direction settings
*/
#define MCI_ST_DATA2DIREN (1 << 2)
#define MCI_ST_CMDDIREN (1 << 3)
#define MCI_ST_DATA0DIREN (1 << 4)
#define MCI_ST_DATA31DIREN (1 << 5)
#define MCI_ST_FBCLKEN (1 << 7)
#define MCI_ST_DATA74DIREN (1 << 8)
#define MMCICLOCK 0x004
#define MCI_CLK_ENABLE (1 << 8)
...
...
@@ -160,7 +150,7 @@
(MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
MCI_TXFIFOHALFEMPTYMASK)
#define NR_SG 1
6
#define NR_SG 1
28
struct
clk
;
struct
variant_data
;
...
...
@@ -189,7 +179,8 @@ struct mmci_host {
unsigned
int
mclk
;
unsigned
int
cclk
;
u32
pwr
;
u32
pwr_reg
;
u32
clk_reg
;
struct
mmci_platform_data
*
plat
;
struct
variant_data
*
variant
;
...
...
include/linux/amba/mmci.h
View file @
bba1594d
...
...
@@ -6,6 +6,19 @@
#include <linux/mmc/host.h>
/*
* These defines is places here due to access is needed from machine
* configuration files. The ST Micro version does not have ROD and
* reuse the voltage registers for direction settings.
*/
#define MCI_ST_DATA2DIREN (1 << 2)
#define MCI_ST_CMDDIREN (1 << 3)
#define MCI_ST_DATA0DIREN (1 << 4)
#define MCI_ST_DATA31DIREN (1 << 5)
#define MCI_ST_FBCLKEN (1 << 7)
#define MCI_ST_DATA74DIREN (1 << 8)
/* Just some dummy forwarding */
struct
dma_chan
;
...
...
@@ -18,7 +31,8 @@ struct dma_chan;
* @ocr_mask: available voltages on the 4 pins from the block, this
* is ignored if a regulator is used, see the MMC_VDD_* masks in
* mmc/host.h
* @vdd_handler: a callback function to translate a MMC_VDD_*
* @ios_handler: a callback function to act on specfic ios changes,
* used for example to control a levelshifter
* mask into a value to be binary (or set some other custom bits
* in MMCIPWR) or:ed and written into the MMCIPWR register of the
* block. May also control external power based on the power_mode.
...
...
@@ -31,6 +45,8 @@ struct dma_chan;
* @capabilities: the capabilities of the block as implemented in
* this platform, signify anything MMC_CAP_* from mmc/host.h
* @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h
* @sigdir: a bit field indicating for what bits in the MMC bus the host
* should enable signal direction indication.
* @dma_filter: function used to select an appropriate RX and TX
* DMA channel to be used for DMA, if and only if you're deploying the
* generic DMA engine
...
...
@@ -46,14 +62,14 @@ struct dma_chan;
struct
mmci_platform_data
{
unsigned
int
f_max
;
unsigned
int
ocr_mask
;
u32
(
*
vdd_handler
)(
struct
device
*
,
unsigned
int
vdd
,
unsigned
char
power_mode
);
int
(
*
ios_handler
)(
struct
device
*
,
struct
mmc_ios
*
);
unsigned
int
(
*
status
)(
struct
device
*
);
int
gpio_wp
;
int
gpio_cd
;
bool
cd_invert
;
unsigned
long
capabilities
;
unsigned
long
capabilities2
;
u32
sigdir
;
bool
(
*
dma_filter
)(
struct
dma_chan
*
chan
,
void
*
filter_param
);
void
*
dma_rx_param
;
void
*
dma_tx_param
;
...
...
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