diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-07 20:17:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-07 20:17:39 -0400 |
commit | 54c72d5987ff9f3cf59529d5d4f5cf19eae3f695 (patch) | |
tree | 3fee972d54926627895aa07684ddb2e2388e4614 /drivers/mmc/host/rtsx_pci_sdmmc.c | |
parent | 66bb0aa077978dbb76e6283531eb3cc7a878de38 (diff) | |
parent | 7caa79917ad4c1f91366b11f18e48623554aaa52 (diff) |
Merge tag 'mfd-for-linus-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD update from Lee Jones:
"Changes to existing drivers:
- checkpatch fixes throughout the subsystem
- use Regmap to handle IRQs in max77686, extcon-max77693 and
mc13xxx-core
- use DMA in rtsx_pcr
- restrict building on unsupported architectures on timberdale,
cs5535
- SPI hardening in cros_ec_spi
- more robust error handing in asic3, cros_ec, ab8500-debugfs,
max77686 and pcf50633-core
- reorder PM runtime and regulator handing during shutdown in arizona
- enable wakeup in cros_ec_spi
- unused variable/code clean-up in pm8921-core, cros_ec, htc-i2cpld,
tps65912-spi, wm5110-tables and ab8500-debugfs
- add regulator handing into suspend() in sec-core
- remove pointless wrapper functions in extcon-max77693 and
i2c-cros-ec-tunnel
- use cross-architecture friendly data sizes in stmpe-i2c, arizona,
max77686 and tps65910
- devicetree documentation updates throughout
- provide power management support in max77686
- few OF clean-ups in max77686
- use manged resources in tps6105x
New drivers/supported devices:
- add support for s2mpu02 to sec-core
- add support for Allwinner A32 to sun6i-prcm
- add support for Maxim 77802 in max77686
- add support for DA9063 AD in da9063
- new driver for Intel PMICs (generic) and specifically Crystal Cove
(Re-)moved drivers ==
- move out keyboard functionality cros_ec ==> input/keyboard/cros_ec_keyb"
* tag 'mfd-for-linus-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (101 commits)
MAINTAINERS: Update MFD repo location
mfd: omap-usb-host: Fix improper mask use.
mfd: arizona: Only free the CTRLIF_ERR IRQ if we requested it
mfd: arizona: Add missing handling for ISRC3 under/overclocked
mfd: wm5110: Add new interrupt register definitions
mfd: arizona: Rename thermal shutdown interrupt
mfd: wm5110: Add in the output done interrupts
mfd: wm5110: Remove non-existant interrupts
mfd: tps65912-spi: Remove unused variable
mfd: htc-i2cpld: Remove unused code
mfd: da9063: Add support for AD silicon variant
mfd: arizona: Map MICVDD from extcon device to the Arizona core
mfd: arizona: Add MICVDD to mapped regulators for wm8997
mfd: max77686: Ensure device type IDs are architecture agnostic
mfd: max77686: Add Maxim 77802 PMIC support
mfd: tps6105x: Use managed resources when allocating memory
mfd: wm8997-tables: Suppress 'line over 80 chars' warnings
mfd: kempld-core: Correct a variety of checkpatch warnings
mfd: ipaq-micro: Fix coding style errors/warnings reported by checkpatch
mfd: si476x-cmd: Remedy checkpatch style complains
...
Diffstat (limited to 'drivers/mmc/host/rtsx_pci_sdmmc.c')
-rw-r--r-- | drivers/mmc/host/rtsx_pci_sdmmc.c | 133 |
1 files changed, 127 insertions, 6 deletions
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 0d519649b575..dfde4a210238 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/highmem.h> | 24 | #include <linux/highmem.h> |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/workqueue.h> | ||
27 | #include <linux/mmc/host.h> | 28 | #include <linux/mmc/host.h> |
28 | #include <linux/mmc/mmc.h> | 29 | #include <linux/mmc/mmc.h> |
29 | #include <linux/mmc/sd.h> | 30 | #include <linux/mmc/sd.h> |
@@ -36,7 +37,10 @@ struct realtek_pci_sdmmc { | |||
36 | struct rtsx_pcr *pcr; | 37 | struct rtsx_pcr *pcr; |
37 | struct mmc_host *mmc; | 38 | struct mmc_host *mmc; |
38 | struct mmc_request *mrq; | 39 | struct mmc_request *mrq; |
40 | struct workqueue_struct *workq; | ||
41 | #define SDMMC_WORKQ_NAME "rtsx_pci_sdmmc_workq" | ||
39 | 42 | ||
43 | struct work_struct work; | ||
40 | struct mutex host_mutex; | 44 | struct mutex host_mutex; |
41 | 45 | ||
42 | u8 ssc_depth; | 46 | u8 ssc_depth; |
@@ -48,6 +52,11 @@ struct realtek_pci_sdmmc { | |||
48 | int power_state; | 52 | int power_state; |
49 | #define SDMMC_POWER_ON 1 | 53 | #define SDMMC_POWER_ON 1 |
50 | #define SDMMC_POWER_OFF 0 | 54 | #define SDMMC_POWER_OFF 0 |
55 | |||
56 | unsigned int sg_count; | ||
57 | s32 cookie; | ||
58 | unsigned int cookie_sg_count; | ||
59 | bool using_cookie; | ||
51 | }; | 60 | }; |
52 | 61 | ||
53 | static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host) | 62 | static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host) |
@@ -86,6 +95,77 @@ static void sd_print_debug_regs(struct realtek_pci_sdmmc *host) | |||
86 | #define sd_print_debug_regs(host) | 95 | #define sd_print_debug_regs(host) |
87 | #endif /* DEBUG */ | 96 | #endif /* DEBUG */ |
88 | 97 | ||
98 | /* | ||
99 | * sd_pre_dma_transfer - do dma_map_sg() or using cookie | ||
100 | * | ||
101 | * @pre: if called in pre_req() | ||
102 | * return: | ||
103 | * 0 - do dma_map_sg() | ||
104 | * 1 - using cookie | ||
105 | */ | ||
106 | static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host, | ||
107 | struct mmc_data *data, bool pre) | ||
108 | { | ||
109 | struct rtsx_pcr *pcr = host->pcr; | ||
110 | int read = data->flags & MMC_DATA_READ; | ||
111 | int count = 0; | ||
112 | int using_cookie = 0; | ||
113 | |||
114 | if (!pre && data->host_cookie && data->host_cookie != host->cookie) { | ||
115 | dev_err(sdmmc_dev(host), | ||
116 | "error: data->host_cookie = %d, host->cookie = %d\n", | ||
117 | data->host_cookie, host->cookie); | ||
118 | data->host_cookie = 0; | ||
119 | } | ||
120 | |||
121 | if (pre || data->host_cookie != host->cookie) { | ||
122 | count = rtsx_pci_dma_map_sg(pcr, data->sg, data->sg_len, read); | ||
123 | } else { | ||
124 | count = host->cookie_sg_count; | ||
125 | using_cookie = 1; | ||
126 | } | ||
127 | |||
128 | if (pre) { | ||
129 | host->cookie_sg_count = count; | ||
130 | if (++host->cookie < 0) | ||
131 | host->cookie = 1; | ||
132 | data->host_cookie = host->cookie; | ||
133 | } else { | ||
134 | host->sg_count = count; | ||
135 | } | ||
136 | |||
137 | return using_cookie; | ||
138 | } | ||
139 | |||
140 | static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, | ||
141 | bool is_first_req) | ||
142 | { | ||
143 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | ||
144 | struct mmc_data *data = mrq->data; | ||
145 | |||
146 | if (data->host_cookie) { | ||
147 | dev_err(sdmmc_dev(host), | ||
148 | "error: reset data->host_cookie = %d\n", | ||
149 | data->host_cookie); | ||
150 | data->host_cookie = 0; | ||
151 | } | ||
152 | |||
153 | sd_pre_dma_transfer(host, data, true); | ||
154 | dev_dbg(sdmmc_dev(host), "pre dma sg: %d\n", host->cookie_sg_count); | ||
155 | } | ||
156 | |||
157 | static void sdmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, | ||
158 | int err) | ||
159 | { | ||
160 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | ||
161 | struct rtsx_pcr *pcr = host->pcr; | ||
162 | struct mmc_data *data = mrq->data; | ||
163 | int read = data->flags & MMC_DATA_READ; | ||
164 | |||
165 | rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len, read); | ||
166 | data->host_cookie = 0; | ||
167 | } | ||
168 | |||
89 | static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, | 169 | static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, |
90 | u8 *buf, int buf_len, int timeout) | 170 | u8 *buf, int buf_len, int timeout) |
91 | { | 171 | { |
@@ -415,7 +495,7 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) | |||
415 | 495 | ||
416 | rtsx_pci_send_cmd_no_wait(pcr); | 496 | rtsx_pci_send_cmd_no_wait(pcr); |
417 | 497 | ||
418 | err = rtsx_pci_transfer_data(pcr, data->sg, data->sg_len, read, 10000); | 498 | err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, read, 10000); |
419 | if (err < 0) { | 499 | if (err < 0) { |
420 | sd_clear_error(host); | 500 | sd_clear_error(host); |
421 | return err; | 501 | return err; |
@@ -640,12 +720,24 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode) | |||
640 | return 0; | 720 | return 0; |
641 | } | 721 | } |
642 | 722 | ||
643 | static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) | 723 | static inline int sd_rw_cmd(struct mmc_command *cmd) |
644 | { | 724 | { |
645 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | 725 | return mmc_op_multi(cmd->opcode) || |
726 | (cmd->opcode == MMC_READ_SINGLE_BLOCK) || | ||
727 | (cmd->opcode == MMC_WRITE_BLOCK); | ||
728 | } | ||
729 | |||
730 | static void sd_request(struct work_struct *work) | ||
731 | { | ||
732 | struct realtek_pci_sdmmc *host = container_of(work, | ||
733 | struct realtek_pci_sdmmc, work); | ||
646 | struct rtsx_pcr *pcr = host->pcr; | 734 | struct rtsx_pcr *pcr = host->pcr; |
735 | |||
736 | struct mmc_host *mmc = host->mmc; | ||
737 | struct mmc_request *mrq = host->mrq; | ||
647 | struct mmc_command *cmd = mrq->cmd; | 738 | struct mmc_command *cmd = mrq->cmd; |
648 | struct mmc_data *data = mrq->data; | 739 | struct mmc_data *data = mrq->data; |
740 | |||
649 | unsigned int data_size = 0; | 741 | unsigned int data_size = 0; |
650 | int err; | 742 | int err; |
651 | 743 | ||
@@ -677,13 +769,13 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
677 | if (mrq->data) | 769 | if (mrq->data) |
678 | data_size = data->blocks * data->blksz; | 770 | data_size = data->blocks * data->blksz; |
679 | 771 | ||
680 | if (!data_size || mmc_op_multi(cmd->opcode) || | 772 | if (!data_size || sd_rw_cmd(cmd)) { |
681 | (cmd->opcode == MMC_READ_SINGLE_BLOCK) || | ||
682 | (cmd->opcode == MMC_WRITE_BLOCK)) { | ||
683 | sd_send_cmd_get_rsp(host, cmd); | 773 | sd_send_cmd_get_rsp(host, cmd); |
684 | 774 | ||
685 | if (!cmd->error && data_size) { | 775 | if (!cmd->error && data_size) { |
686 | sd_rw_multi(host, mrq); | 776 | sd_rw_multi(host, mrq); |
777 | if (!host->using_cookie) | ||
778 | sdmmc_post_req(host->mmc, host->mrq, 0); | ||
687 | 779 | ||
688 | if (mmc_op_multi(cmd->opcode) && mrq->stop) | 780 | if (mmc_op_multi(cmd->opcode) && mrq->stop) |
689 | sd_send_cmd_get_rsp(host, mrq->stop); | 781 | sd_send_cmd_get_rsp(host, mrq->stop); |
@@ -712,6 +804,21 @@ finish: | |||
712 | mmc_request_done(mmc, mrq); | 804 | mmc_request_done(mmc, mrq); |
713 | } | 805 | } |
714 | 806 | ||
807 | static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) | ||
808 | { | ||
809 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | ||
810 | struct mmc_data *data = mrq->data; | ||
811 | |||
812 | mutex_lock(&host->host_mutex); | ||
813 | host->mrq = mrq; | ||
814 | mutex_unlock(&host->host_mutex); | ||
815 | |||
816 | if (sd_rw_cmd(mrq->cmd)) | ||
817 | host->using_cookie = sd_pre_dma_transfer(host, data, false); | ||
818 | |||
819 | queue_work(host->workq, &host->work); | ||
820 | } | ||
821 | |||
715 | static int sd_set_bus_width(struct realtek_pci_sdmmc *host, | 822 | static int sd_set_bus_width(struct realtek_pci_sdmmc *host, |
716 | unsigned char bus_width) | 823 | unsigned char bus_width) |
717 | { | 824 | { |
@@ -1146,6 +1253,8 @@ out: | |||
1146 | } | 1253 | } |
1147 | 1254 | ||
1148 | static const struct mmc_host_ops realtek_pci_sdmmc_ops = { | 1255 | static const struct mmc_host_ops realtek_pci_sdmmc_ops = { |
1256 | .pre_req = sdmmc_pre_req, | ||
1257 | .post_req = sdmmc_post_req, | ||
1149 | .request = sdmmc_request, | 1258 | .request = sdmmc_request, |
1150 | .set_ios = sdmmc_set_ios, | 1259 | .set_ios = sdmmc_set_ios, |
1151 | .get_ro = sdmmc_get_ro, | 1260 | .get_ro = sdmmc_get_ro, |
@@ -1224,10 +1333,16 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) | |||
1224 | return -ENOMEM; | 1333 | return -ENOMEM; |
1225 | 1334 | ||
1226 | host = mmc_priv(mmc); | 1335 | host = mmc_priv(mmc); |
1336 | host->workq = create_singlethread_workqueue(SDMMC_WORKQ_NAME); | ||
1337 | if (!host->workq) { | ||
1338 | mmc_free_host(mmc); | ||
1339 | return -ENOMEM; | ||
1340 | } | ||
1227 | host->pcr = pcr; | 1341 | host->pcr = pcr; |
1228 | host->mmc = mmc; | 1342 | host->mmc = mmc; |
1229 | host->pdev = pdev; | 1343 | host->pdev = pdev; |
1230 | host->power_state = SDMMC_POWER_OFF; | 1344 | host->power_state = SDMMC_POWER_OFF; |
1345 | INIT_WORK(&host->work, sd_request); | ||
1231 | platform_set_drvdata(pdev, host); | 1346 | platform_set_drvdata(pdev, host); |
1232 | pcr->slots[RTSX_SD_CARD].p_dev = pdev; | 1347 | pcr->slots[RTSX_SD_CARD].p_dev = pdev; |
1233 | pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event; | 1348 | pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event; |
@@ -1255,6 +1370,8 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) | |||
1255 | pcr->slots[RTSX_SD_CARD].card_event = NULL; | 1370 | pcr->slots[RTSX_SD_CARD].card_event = NULL; |
1256 | mmc = host->mmc; | 1371 | mmc = host->mmc; |
1257 | 1372 | ||
1373 | cancel_work_sync(&host->work); | ||
1374 | |||
1258 | mutex_lock(&host->host_mutex); | 1375 | mutex_lock(&host->host_mutex); |
1259 | if (host->mrq) { | 1376 | if (host->mrq) { |
1260 | dev_dbg(&(pdev->dev), | 1377 | dev_dbg(&(pdev->dev), |
@@ -1273,6 +1390,10 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) | |||
1273 | mmc_remove_host(mmc); | 1390 | mmc_remove_host(mmc); |
1274 | host->eject = true; | 1391 | host->eject = true; |
1275 | 1392 | ||
1393 | flush_workqueue(host->workq); | ||
1394 | destroy_workqueue(host->workq); | ||
1395 | host->workq = NULL; | ||
1396 | |||
1276 | mmc_free_host(mmc); | 1397 | mmc_free_host(mmc); |
1277 | 1398 | ||
1278 | dev_dbg(&(pdev->dev), | 1399 | dev_dbg(&(pdev->dev), |