Merge branch 'fixes' of git://git.linaro.org/people/rmk/linux-arm
[linux-2.6.git] / drivers / mfd / rtl8411.c
blobc436bf27e78d232340825ad12bf9d493d9ae26a2
1 /* Driver for Realtek PCI-Express card reader
3 * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2, or (at your option) any
8 * later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, see <http://www.gnu.org/licenses/>.
18 * Author:
19 * Wei WANG <wei_wang@realsil.com.cn>
20 * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
23 #include <linux/module.h>
24 #include <linux/bitops.h>
25 #include <linux/delay.h>
26 #include <linux/mfd/rtsx_pci.h>
28 #include "rtsx_pcr.h"
30 static u8 rtl8411_get_ic_version(struct rtsx_pcr *pcr)
32 u8 val;
34 rtsx_pci_read_register(pcr, SYS_VER, &val);
35 return val & 0x0F;
38 static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr)
40 u8 val = 0;
42 rtsx_pci_read_register(pcr, RTL8411B_PACKAGE_MODE, &val);
44 if (val & 0x2)
45 return 1;
46 else
47 return 0;
50 static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr)
52 return rtsx_pci_write_register(pcr, CD_PAD_CTL,
53 CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
56 static int rtl8411b_extra_init_hw(struct rtsx_pcr *pcr)
58 if (rtl8411b_is_qfn48(pcr))
59 rtsx_pci_write_register(pcr, CARD_PULL_CTL3, 0xFF, 0xF5);
61 return rtsx_pci_write_register(pcr, CD_PAD_CTL,
62 CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
65 static int rtl8411_turn_on_led(struct rtsx_pcr *pcr)
67 return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00);
70 static int rtl8411_turn_off_led(struct rtsx_pcr *pcr)
72 return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01);
75 static int rtl8411_enable_auto_blink(struct rtsx_pcr *pcr)
77 return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D);
80 static int rtl8411_disable_auto_blink(struct rtsx_pcr *pcr)
82 return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00);
85 static int rtl8411_card_power_on(struct rtsx_pcr *pcr, int card)
87 int err;
89 rtsx_pci_init_cmd(pcr);
90 rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
91 BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON);
92 rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CTL,
93 BPP_LDO_POWB, BPP_LDO_SUSPEND);
94 err = rtsx_pci_send_cmd(pcr, 100);
95 if (err < 0)
96 return err;
98 /* To avoid too large in-rush current */
99 udelay(150);
101 err = rtsx_pci_write_register(pcr, CARD_PWR_CTL,
102 BPP_POWER_MASK, BPP_POWER_10_PERCENT_ON);
103 if (err < 0)
104 return err;
106 udelay(150);
108 err = rtsx_pci_write_register(pcr, CARD_PWR_CTL,
109 BPP_POWER_MASK, BPP_POWER_15_PERCENT_ON);
110 if (err < 0)
111 return err;
113 udelay(150);
115 err = rtsx_pci_write_register(pcr, CARD_PWR_CTL,
116 BPP_POWER_MASK, BPP_POWER_ON);
117 if (err < 0)
118 return err;
120 return rtsx_pci_write_register(pcr, LDO_CTL, BPP_LDO_POWB, BPP_LDO_ON);
123 static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card)
125 int err;
127 err = rtsx_pci_write_register(pcr, CARD_PWR_CTL,
128 BPP_POWER_MASK, BPP_POWER_OFF);
129 if (err < 0)
130 return err;
132 return rtsx_pci_write_register(pcr, LDO_CTL,
133 BPP_LDO_POWB, BPP_LDO_SUSPEND);
136 static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
138 u8 mask, val;
139 int err;
141 mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK;
142 if (voltage == OUTPUT_3V3) {
143 err = rtsx_pci_write_register(pcr,
144 SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
145 if (err < 0)
146 return err;
147 val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3;
148 } else if (voltage == OUTPUT_1V8) {
149 err = rtsx_pci_write_register(pcr,
150 SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
151 if (err < 0)
152 return err;
153 val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8;
154 } else {
155 return -EINVAL;
158 return rtsx_pci_write_register(pcr, LDO_CTL, mask, val);
161 static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr)
163 unsigned int card_exist;
165 card_exist = rtsx_pci_readl(pcr, RTSX_BIPR);
166 card_exist &= CARD_EXIST;
167 if (!card_exist) {
168 /* Enable card CD */
169 rtsx_pci_write_register(pcr, CD_PAD_CTL,
170 CD_DISABLE_MASK, CD_ENABLE);
171 /* Enable card interrupt */
172 rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x00);
173 return 0;
176 if (hweight32(card_exist) > 1) {
177 rtsx_pci_write_register(pcr, CARD_PWR_CTL,
178 BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON);
179 msleep(100);
181 card_exist = rtsx_pci_readl(pcr, RTSX_BIPR);
182 if (card_exist & MS_EXIST)
183 card_exist = MS_EXIST;
184 else if (card_exist & SD_EXIST)
185 card_exist = SD_EXIST;
186 else
187 card_exist = 0;
189 rtsx_pci_write_register(pcr, CARD_PWR_CTL,
190 BPP_POWER_MASK, BPP_POWER_OFF);
192 dev_dbg(&(pcr->pci->dev),
193 "After CD deglitch, card_exist = 0x%x\n",
194 card_exist);
197 if (card_exist & MS_EXIST) {
198 /* Disable SD interrupt */
199 rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x40);
200 rtsx_pci_write_register(pcr, CD_PAD_CTL,
201 CD_DISABLE_MASK, MS_CD_EN_ONLY);
202 } else if (card_exist & SD_EXIST) {
203 /* Disable MS interrupt */
204 rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x80);
205 rtsx_pci_write_register(pcr, CD_PAD_CTL,
206 CD_DISABLE_MASK, SD_CD_EN_ONLY);
209 return card_exist;
212 static int rtl8411_conv_clk_and_div_n(int input, int dir)
214 int output;
216 if (dir == CLK_TO_DIV_N)
217 output = input * 4 / 5 - 2;
218 else
219 output = (input + 2) * 5 / 4;
221 return output;
224 static const struct pcr_ops rtl8411_pcr_ops = {
225 .extra_init_hw = rtl8411_extra_init_hw,
226 .optimize_phy = NULL,
227 .turn_on_led = rtl8411_turn_on_led,
228 .turn_off_led = rtl8411_turn_off_led,
229 .enable_auto_blink = rtl8411_enable_auto_blink,
230 .disable_auto_blink = rtl8411_disable_auto_blink,
231 .card_power_on = rtl8411_card_power_on,
232 .card_power_off = rtl8411_card_power_off,
233 .switch_output_voltage = rtl8411_switch_output_voltage,
234 .cd_deglitch = rtl8411_cd_deglitch,
235 .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
238 static const struct pcr_ops rtl8411b_pcr_ops = {
239 .extra_init_hw = rtl8411b_extra_init_hw,
240 .optimize_phy = NULL,
241 .turn_on_led = rtl8411_turn_on_led,
242 .turn_off_led = rtl8411_turn_off_led,
243 .enable_auto_blink = rtl8411_enable_auto_blink,
244 .disable_auto_blink = rtl8411_disable_auto_blink,
245 .card_power_on = rtl8411_card_power_on,
246 .card_power_off = rtl8411_card_power_off,
247 .switch_output_voltage = rtl8411_switch_output_voltage,
248 .cd_deglitch = rtl8411_cd_deglitch,
249 .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
252 /* SD Pull Control Enable:
253 * SD_DAT[3:0] ==> pull up
254 * SD_CD ==> pull up
255 * SD_WP ==> pull up
256 * SD_CMD ==> pull up
257 * SD_CLK ==> pull down
259 static const u32 rtl8411_sd_pull_ctl_enable_tbl[] = {
260 RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA),
261 RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
262 RTSX_REG_PAIR(CARD_PULL_CTL3, 0xA9),
263 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09),
264 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x09),
265 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04),
269 /* SD Pull Control Disable:
270 * SD_DAT[3:0] ==> pull down
271 * SD_CD ==> pull up
272 * SD_WP ==> pull down
273 * SD_CMD ==> pull down
274 * SD_CLK ==> pull down
276 static const u32 rtl8411_sd_pull_ctl_disable_tbl[] = {
277 RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
278 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
279 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95),
280 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09),
281 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05),
282 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04),
286 /* MS Pull Control Enable:
287 * MS CD ==> pull up
288 * others ==> pull down
290 static const u32 rtl8411_ms_pull_ctl_enable_tbl[] = {
291 RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
292 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
293 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95),
294 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05),
295 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05),
296 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04),
300 /* MS Pull Control Disable:
301 * MS CD ==> pull up
302 * others ==> pull down
304 static const u32 rtl8411_ms_pull_ctl_disable_tbl[] = {
305 RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
306 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
307 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95),
308 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09),
309 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05),
310 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04),
314 static const u32 rtl8411b_qfn64_sd_pull_ctl_enable_tbl[] = {
315 RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA),
316 RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
317 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x09 | 0xD0),
318 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
319 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
320 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
324 static const u32 rtl8411b_qfn48_sd_pull_ctl_enable_tbl[] = {
325 RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
326 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x69 | 0x90),
327 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x08 | 0x11),
331 static const u32 rtl8411b_qfn64_sd_pull_ctl_disable_tbl[] = {
332 RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
333 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
334 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
335 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
336 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
337 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
341 static const u32 rtl8411b_qfn48_sd_pull_ctl_disable_tbl[] = {
342 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
343 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
344 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
348 static const u32 rtl8411b_qfn64_ms_pull_ctl_enable_tbl[] = {
349 RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
350 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
351 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
352 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05 | 0x50),
353 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
354 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
358 static const u32 rtl8411b_qfn48_ms_pull_ctl_enable_tbl[] = {
359 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
360 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
361 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
365 static const u32 rtl8411b_qfn64_ms_pull_ctl_disable_tbl[] = {
366 RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
367 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
368 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
369 RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
370 RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
371 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
375 static const u32 rtl8411b_qfn48_ms_pull_ctl_disable_tbl[] = {
376 RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
377 RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
378 RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
382 void rtl8411_init_params(struct rtsx_pcr *pcr)
384 pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
385 pcr->num_slots = 2;
386 pcr->ops = &rtl8411_pcr_ops;
388 pcr->ic_version = rtl8411_get_ic_version(pcr);
389 pcr->sd_pull_ctl_enable_tbl = rtl8411_sd_pull_ctl_enable_tbl;
390 pcr->sd_pull_ctl_disable_tbl = rtl8411_sd_pull_ctl_disable_tbl;
391 pcr->ms_pull_ctl_enable_tbl = rtl8411_ms_pull_ctl_enable_tbl;
392 pcr->ms_pull_ctl_disable_tbl = rtl8411_ms_pull_ctl_disable_tbl;
395 void rtl8411b_init_params(struct rtsx_pcr *pcr)
397 pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
398 pcr->num_slots = 2;
399 pcr->ops = &rtl8411b_pcr_ops;
401 pcr->ic_version = rtl8411_get_ic_version(pcr);
403 if (rtl8411b_is_qfn48(pcr)) {
404 pcr->sd_pull_ctl_enable_tbl =
405 rtl8411b_qfn48_sd_pull_ctl_enable_tbl;
406 pcr->sd_pull_ctl_disable_tbl =
407 rtl8411b_qfn48_sd_pull_ctl_disable_tbl;
408 pcr->ms_pull_ctl_enable_tbl =
409 rtl8411b_qfn48_ms_pull_ctl_enable_tbl;
410 pcr->ms_pull_ctl_disable_tbl =
411 rtl8411b_qfn48_ms_pull_ctl_disable_tbl;
412 } else {
413 pcr->sd_pull_ctl_enable_tbl =
414 rtl8411b_qfn64_sd_pull_ctl_enable_tbl;
415 pcr->sd_pull_ctl_disable_tbl =
416 rtl8411b_qfn64_sd_pull_ctl_disable_tbl;
417 pcr->ms_pull_ctl_enable_tbl =
418 rtl8411b_qfn64_ms_pull_ctl_enable_tbl;
419 pcr->ms_pull_ctl_disable_tbl =
420 rtl8411b_qfn64_ms_pull_ctl_disable_tbl;