sdio.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. /*
  2. * Sonics Silicon Backplane
  3. * SDIO-Hostbus related functions
  4. *
  5. * Copyright 2009 Albert Herranz <albert_herranz@yahoo.es>
  6. *
  7. * Based on drivers/ssb/pcmcia.c
  8. * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
  9. * Copyright 2007-2008 Michael Buesch <m@bues.ch>
  10. *
  11. * Licensed under the GNU/GPL. See COPYING for details.
  12. *
  13. */
  14. #include <linux/ssb/ssb.h>
  15. #include <linux/delay.h>
  16. #include <linux/io.h>
  17. #include <linux/etherdevice.h>
  18. #include <linux/mmc/sdio_func.h>
  19. #include "ssb_private.h"
  20. /* Define the following to 1 to enable a printk on each coreswitch. */
  21. #define SSB_VERBOSE_SDIOCORESWITCH_DEBUG 0
  22. /* Hardware invariants CIS tuples */
  23. #define SSB_SDIO_CIS 0x80
  24. #define SSB_SDIO_CIS_SROMREV 0x00
  25. #define SSB_SDIO_CIS_ID 0x01
  26. #define SSB_SDIO_CIS_BOARDREV 0x02
  27. #define SSB_SDIO_CIS_PA 0x03
  28. #define SSB_SDIO_CIS_PA_PA0B0_LO 0
  29. #define SSB_SDIO_CIS_PA_PA0B0_HI 1
  30. #define SSB_SDIO_CIS_PA_PA0B1_LO 2
  31. #define SSB_SDIO_CIS_PA_PA0B1_HI 3
  32. #define SSB_SDIO_CIS_PA_PA0B2_LO 4
  33. #define SSB_SDIO_CIS_PA_PA0B2_HI 5
  34. #define SSB_SDIO_CIS_PA_ITSSI 6
  35. #define SSB_SDIO_CIS_PA_MAXPOW 7
  36. #define SSB_SDIO_CIS_OEMNAME 0x04
  37. #define SSB_SDIO_CIS_CCODE 0x05
  38. #define SSB_SDIO_CIS_ANTENNA 0x06
  39. #define SSB_SDIO_CIS_ANTGAIN 0x07
  40. #define SSB_SDIO_CIS_BFLAGS 0x08
  41. #define SSB_SDIO_CIS_LEDS 0x09
  42. #define CISTPL_FUNCE_LAN_NODE_ID 0x04 /* same as in PCMCIA */
  43. /*
  44. * Function 1 miscellaneous registers.
  45. *
  46. * Definitions match src/include/sbsdio.h from the
  47. * Android Open Source Project
  48. * http://android.git.kernel.org/?p=platform/system/wlan/broadcom.git
  49. *
  50. */
  51. #define SBSDIO_FUNC1_SBADDRLOW 0x1000a /* SB Address window Low (b15) */
  52. #define SBSDIO_FUNC1_SBADDRMID 0x1000b /* SB Address window Mid (b23-b16) */
  53. #define SBSDIO_FUNC1_SBADDRHIGH 0x1000c /* SB Address window High (b24-b31) */
  54. /* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */
  55. #define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid address bits in SBADDRLOW */
  56. #define SBSDIO_SBADDRMID_MASK 0xff /* Valid address bits in SBADDRMID */
  57. #define SBSDIO_SBADDRHIGH_MASK 0xff /* Valid address bits in SBADDRHIGH */
  58. #define SBSDIO_SB_OFT_ADDR_MASK 0x7FFF /* sb offset addr is <= 15 bits, 32k */
  59. /* REVISIT: this flag doesn't seem to matter */
  60. #define SBSDIO_SB_ACCESS_2_4B_FLAG 0x8000 /* forces 32-bit SB access */
  61. /*
  62. * Address map within the SDIO function address space (128K).
  63. *
  64. * Start End Description
  65. * ------- ------- ------------------------------------------
  66. * 0x00000 0x0ffff selected backplane address window (64K)
  67. * 0x10000 0x1ffff backplane control registers (max 64K)
  68. *
  69. * The current address window is configured by writing to registers
  70. * SBADDRLOW, SBADDRMID and SBADDRHIGH.
  71. *
  72. * In order to access the contents of a 32-bit Silicon Backplane address
  73. * the backplane address window must be first loaded with the highest
  74. * 16 bits of the target address. Then, an access must be done to the
  75. * SDIO function address space using the lower 15 bits of the address.
  76. * Bit 15 of the address must be set when doing 32 bit accesses.
  77. *
  78. * 10987654321098765432109876543210
  79. * WWWWWWWWWWWWWWWWW SB Address Window
  80. * OOOOOOOOOOOOOOOO Offset within SB Address Window
  81. * a 32-bit access flag
  82. */
  83. /*
  84. * SSB I/O via SDIO.
  85. *
  86. * NOTE: SDIO address @addr is 17 bits long (SDIO address space is 128K).
  87. */
  88. static inline struct device *ssb_sdio_dev(struct ssb_bus *bus)
  89. {
  90. return &bus->host_sdio->dev;
  91. }
  92. /* host claimed */
  93. static int ssb_sdio_writeb(struct ssb_bus *bus, unsigned int addr, u8 val)
  94. {
  95. int error = 0;
  96. sdio_writeb(bus->host_sdio, val, addr, &error);
  97. if (unlikely(error)) {
  98. dev_dbg(ssb_sdio_dev(bus), "%08X <- %02x, error %d\n",
  99. addr, val, error);
  100. }
  101. return error;
  102. }
  103. #if 0
  104. static u8 ssb_sdio_readb(struct ssb_bus *bus, unsigned int addr)
  105. {
  106. u8 val;
  107. int error = 0;
  108. val = sdio_readb(bus->host_sdio, addr, &error);
  109. if (unlikely(error)) {
  110. dev_dbg(ssb_sdio_dev(bus), "%08X -> %02x, error %d\n",
  111. addr, val, error);
  112. }
  113. return val;
  114. }
  115. #endif
  116. /* host claimed */
  117. static int ssb_sdio_set_sbaddr_window(struct ssb_bus *bus, u32 address)
  118. {
  119. int error;
  120. error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRLOW,
  121. (address >> 8) & SBSDIO_SBADDRLOW_MASK);
  122. if (error)
  123. goto out;
  124. error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRMID,
  125. (address >> 16) & SBSDIO_SBADDRMID_MASK);
  126. if (error)
  127. goto out;
  128. error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRHIGH,
  129. (address >> 24) & SBSDIO_SBADDRHIGH_MASK);
  130. if (error)
  131. goto out;
  132. bus->sdio_sbaddr = address;
  133. out:
  134. if (error) {
  135. dev_dbg(ssb_sdio_dev(bus), "failed to set address window"
  136. " to 0x%08x, error %d\n", address, error);
  137. }
  138. return error;
  139. }
  140. /* for enumeration use only */
  141. u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset)
  142. {
  143. u32 val;
  144. int error;
  145. sdio_claim_host(bus->host_sdio);
  146. val = sdio_readl(bus->host_sdio, offset, &error);
  147. sdio_release_host(bus->host_sdio);
  148. if (unlikely(error)) {
  149. dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n",
  150. bus->sdio_sbaddr >> 16, offset, val, error);
  151. }
  152. return val;
  153. }
  154. /* for enumeration use only */
  155. int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
  156. {
  157. u32 sbaddr;
  158. int error;
  159. sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
  160. sdio_claim_host(bus->host_sdio);
  161. error = ssb_sdio_set_sbaddr_window(bus, sbaddr);
  162. sdio_release_host(bus->host_sdio);
  163. if (error) {
  164. dev_err(ssb_sdio_dev(bus), "failed to switch to core %u,"
  165. " error %d\n", coreidx, error);
  166. goto out;
  167. }
  168. out:
  169. return error;
  170. }
  171. /* host must be already claimed */
  172. static int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
  173. {
  174. u8 coreidx = dev->core_index;
  175. u32 sbaddr;
  176. int error = 0;
  177. sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
  178. if (unlikely(bus->sdio_sbaddr != sbaddr)) {
  179. #if SSB_VERBOSE_SDIOCORESWITCH_DEBUG
  180. dev_info(ssb_sdio_dev(bus),
  181. "switching to %s core, index %d\n",
  182. ssb_core_name(dev->id.coreid), coreidx);
  183. #endif
  184. error = ssb_sdio_set_sbaddr_window(bus, sbaddr);
  185. if (error) {
  186. dev_dbg(ssb_sdio_dev(bus), "failed to switch to"
  187. " core %u, error %d\n", coreidx, error);
  188. goto out;
  189. }
  190. bus->mapped_device = dev;
  191. }
  192. out:
  193. return error;
  194. }
  195. static u8 ssb_sdio_read8(struct ssb_device *dev, u16 offset)
  196. {
  197. struct ssb_bus *bus = dev->bus;
  198. u8 val = 0xff;
  199. int error = 0;
  200. sdio_claim_host(bus->host_sdio);
  201. if (unlikely(ssb_sdio_switch_core(bus, dev)))
  202. goto out;
  203. offset |= bus->sdio_sbaddr & 0xffff;
  204. offset &= SBSDIO_SB_OFT_ADDR_MASK;
  205. val = sdio_readb(bus->host_sdio, offset, &error);
  206. if (error) {
  207. dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %02x, error %d\n",
  208. bus->sdio_sbaddr >> 16, offset, val, error);
  209. }
  210. out:
  211. sdio_release_host(bus->host_sdio);
  212. return val;
  213. }
  214. static u16 ssb_sdio_read16(struct ssb_device *dev, u16 offset)
  215. {
  216. struct ssb_bus *bus = dev->bus;
  217. u16 val = 0xffff;
  218. int error = 0;
  219. sdio_claim_host(bus->host_sdio);
  220. if (unlikely(ssb_sdio_switch_core(bus, dev)))
  221. goto out;
  222. offset |= bus->sdio_sbaddr & 0xffff;
  223. offset &= SBSDIO_SB_OFT_ADDR_MASK;
  224. val = sdio_readw(bus->host_sdio, offset, &error);
  225. if (error) {
  226. dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %04x, error %d\n",
  227. bus->sdio_sbaddr >> 16, offset, val, error);
  228. }
  229. out:
  230. sdio_release_host(bus->host_sdio);
  231. return val;
  232. }
  233. static u32 ssb_sdio_read32(struct ssb_device *dev, u16 offset)
  234. {
  235. struct ssb_bus *bus = dev->bus;
  236. u32 val = 0xffffffff;
  237. int error = 0;
  238. sdio_claim_host(bus->host_sdio);
  239. if (unlikely(ssb_sdio_switch_core(bus, dev)))
  240. goto out;
  241. offset |= bus->sdio_sbaddr & 0xffff;
  242. offset &= SBSDIO_SB_OFT_ADDR_MASK;
  243. offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */
  244. val = sdio_readl(bus->host_sdio, offset, &error);
  245. if (error) {
  246. dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n",
  247. bus->sdio_sbaddr >> 16, offset, val, error);
  248. }
  249. out:
  250. sdio_release_host(bus->host_sdio);
  251. return val;
  252. }
  253. #ifdef CONFIG_SSB_BLOCKIO
  254. static void ssb_sdio_block_read(struct ssb_device *dev, void *buffer,
  255. size_t count, u16 offset, u8 reg_width)
  256. {
  257. size_t saved_count = count;
  258. struct ssb_bus *bus = dev->bus;
  259. int error = 0;
  260. sdio_claim_host(bus->host_sdio);
  261. if (unlikely(ssb_sdio_switch_core(bus, dev))) {
  262. error = -EIO;
  263. memset(buffer, 0xff, count);
  264. goto err_out;
  265. }
  266. offset |= bus->sdio_sbaddr & 0xffff;
  267. offset &= SBSDIO_SB_OFT_ADDR_MASK;
  268. switch (reg_width) {
  269. case sizeof(u8): {
  270. error = sdio_readsb(bus->host_sdio, buffer, offset, count);
  271. break;
  272. }
  273. case sizeof(u16): {
  274. SSB_WARN_ON(count & 1);
  275. error = sdio_readsb(bus->host_sdio, buffer, offset, count);
  276. break;
  277. }
  278. case sizeof(u32): {
  279. SSB_WARN_ON(count & 3);
  280. offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */
  281. error = sdio_readsb(bus->host_sdio, buffer, offset, count);
  282. break;
  283. }
  284. default:
  285. SSB_WARN_ON(1);
  286. }
  287. if (!error)
  288. goto out;
  289. err_out:
  290. dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%zu), error %d\n",
  291. bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error);
  292. out:
  293. sdio_release_host(bus->host_sdio);
  294. }
  295. #endif /* CONFIG_SSB_BLOCKIO */
  296. static void ssb_sdio_write8(struct ssb_device *dev, u16 offset, u8 val)
  297. {
  298. struct ssb_bus *bus = dev->bus;
  299. int error = 0;
  300. sdio_claim_host(bus->host_sdio);
  301. if (unlikely(ssb_sdio_switch_core(bus, dev)))
  302. goto out;
  303. offset |= bus->sdio_sbaddr & 0xffff;
  304. offset &= SBSDIO_SB_OFT_ADDR_MASK;
  305. sdio_writeb(bus->host_sdio, val, offset, &error);
  306. if (error) {
  307. dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %02x, error %d\n",
  308. bus->sdio_sbaddr >> 16, offset, val, error);
  309. }
  310. out:
  311. sdio_release_host(bus->host_sdio);
  312. }
  313. static void ssb_sdio_write16(struct ssb_device *dev, u16 offset, u16 val)
  314. {
  315. struct ssb_bus *bus = dev->bus;
  316. int error = 0;
  317. sdio_claim_host(bus->host_sdio);
  318. if (unlikely(ssb_sdio_switch_core(bus, dev)))
  319. goto out;
  320. offset |= bus->sdio_sbaddr & 0xffff;
  321. offset &= SBSDIO_SB_OFT_ADDR_MASK;
  322. sdio_writew(bus->host_sdio, val, offset, &error);
  323. if (error) {
  324. dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %04x, error %d\n",
  325. bus->sdio_sbaddr >> 16, offset, val, error);
  326. }
  327. out:
  328. sdio_release_host(bus->host_sdio);
  329. }
  330. static void ssb_sdio_write32(struct ssb_device *dev, u16 offset, u32 val)
  331. {
  332. struct ssb_bus *bus = dev->bus;
  333. int error = 0;
  334. sdio_claim_host(bus->host_sdio);
  335. if (unlikely(ssb_sdio_switch_core(bus, dev)))
  336. goto out;
  337. offset |= bus->sdio_sbaddr & 0xffff;
  338. offset &= SBSDIO_SB_OFT_ADDR_MASK;
  339. offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */
  340. sdio_writel(bus->host_sdio, val, offset, &error);
  341. if (error) {
  342. dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %08x, error %d\n",
  343. bus->sdio_sbaddr >> 16, offset, val, error);
  344. }
  345. if (bus->quirks & SSB_QUIRK_SDIO_READ_AFTER_WRITE32)
  346. sdio_readl(bus->host_sdio, 0, &error);
  347. out:
  348. sdio_release_host(bus->host_sdio);
  349. }
  350. #ifdef CONFIG_SSB_BLOCKIO
  351. static void ssb_sdio_block_write(struct ssb_device *dev, const void *buffer,
  352. size_t count, u16 offset, u8 reg_width)
  353. {
  354. size_t saved_count = count;
  355. struct ssb_bus *bus = dev->bus;
  356. int error = 0;
  357. sdio_claim_host(bus->host_sdio);
  358. if (unlikely(ssb_sdio_switch_core(bus, dev))) {
  359. error = -EIO;
  360. memset((void *)buffer, 0xff, count);
  361. goto err_out;
  362. }
  363. offset |= bus->sdio_sbaddr & 0xffff;
  364. offset &= SBSDIO_SB_OFT_ADDR_MASK;
  365. switch (reg_width) {
  366. case sizeof(u8):
  367. error = sdio_writesb(bus->host_sdio, offset,
  368. (void *)buffer, count);
  369. break;
  370. case sizeof(u16):
  371. SSB_WARN_ON(count & 1);
  372. error = sdio_writesb(bus->host_sdio, offset,
  373. (void *)buffer, count);
  374. break;
  375. case sizeof(u32):
  376. SSB_WARN_ON(count & 3);
  377. offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */
  378. error = sdio_writesb(bus->host_sdio, offset,
  379. (void *)buffer, count);
  380. break;
  381. default:
  382. SSB_WARN_ON(1);
  383. }
  384. if (!error)
  385. goto out;
  386. err_out:
  387. dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%zu), error %d\n",
  388. bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error);
  389. out:
  390. sdio_release_host(bus->host_sdio);
  391. }
  392. #endif /* CONFIG_SSB_BLOCKIO */
  393. /* Not "static", as it's used in main.c */
  394. const struct ssb_bus_ops ssb_sdio_ops = {
  395. .read8 = ssb_sdio_read8,
  396. .read16 = ssb_sdio_read16,
  397. .read32 = ssb_sdio_read32,
  398. .write8 = ssb_sdio_write8,
  399. .write16 = ssb_sdio_write16,
  400. .write32 = ssb_sdio_write32,
  401. #ifdef CONFIG_SSB_BLOCKIO
  402. .block_read = ssb_sdio_block_read,
  403. .block_write = ssb_sdio_block_write,
  404. #endif
  405. };
  406. #define GOTO_ERROR_ON(condition, description) do { \
  407. if (unlikely(condition)) { \
  408. error_description = description; \
  409. goto error; \
  410. } \
  411. } while (0)
  412. int ssb_sdio_get_invariants(struct ssb_bus *bus,
  413. struct ssb_init_invariants *iv)
  414. {
  415. struct ssb_sprom *sprom = &iv->sprom;
  416. struct ssb_boardinfo *bi = &iv->boardinfo;
  417. const char *error_description = "none";
  418. struct sdio_func_tuple *tuple;
  419. void *mac;
  420. memset(sprom, 0xFF, sizeof(*sprom));
  421. sprom->boardflags_lo = 0;
  422. sprom->boardflags_hi = 0;
  423. tuple = bus->host_sdio->tuples;
  424. while (tuple) {
  425. switch (tuple->code) {
  426. case 0x22: /* extended function */
  427. switch (tuple->data[0]) {
  428. case CISTPL_FUNCE_LAN_NODE_ID:
  429. GOTO_ERROR_ON((tuple->size != 7) &&
  430. (tuple->data[1] != 6),
  431. "mac tpl size");
  432. /* fetch the MAC address. */
  433. mac = tuple->data + 2;
  434. memcpy(sprom->il0mac, mac, ETH_ALEN);
  435. memcpy(sprom->et1mac, mac, ETH_ALEN);
  436. break;
  437. default:
  438. break;
  439. }
  440. break;
  441. case 0x80: /* vendor specific tuple */
  442. switch (tuple->data[0]) {
  443. case SSB_SDIO_CIS_SROMREV:
  444. GOTO_ERROR_ON(tuple->size != 2,
  445. "sromrev tpl size");
  446. sprom->revision = tuple->data[1];
  447. break;
  448. case SSB_SDIO_CIS_ID:
  449. GOTO_ERROR_ON((tuple->size != 5) &&
  450. (tuple->size != 7),
  451. "id tpl size");
  452. bi->vendor = tuple->data[1] |
  453. (tuple->data[2]<<8);
  454. break;
  455. case SSB_SDIO_CIS_BOARDREV:
  456. GOTO_ERROR_ON(tuple->size != 2,
  457. "boardrev tpl size");
  458. sprom->board_rev = tuple->data[1];
  459. break;
  460. case SSB_SDIO_CIS_PA:
  461. GOTO_ERROR_ON((tuple->size != 9) &&
  462. (tuple->size != 10),
  463. "pa tpl size");
  464. sprom->pa0b0 = tuple->data[1] |
  465. ((u16)tuple->data[2] << 8);
  466. sprom->pa0b1 = tuple->data[3] |
  467. ((u16)tuple->data[4] << 8);
  468. sprom->pa0b2 = tuple->data[5] |
  469. ((u16)tuple->data[6] << 8);
  470. sprom->itssi_a = tuple->data[7];
  471. sprom->itssi_bg = tuple->data[7];
  472. sprom->maxpwr_a = tuple->data[8];
  473. sprom->maxpwr_bg = tuple->data[8];
  474. break;
  475. case SSB_SDIO_CIS_OEMNAME:
  476. /* Not present */
  477. break;
  478. case SSB_SDIO_CIS_CCODE:
  479. GOTO_ERROR_ON(tuple->size != 2,
  480. "ccode tpl size");
  481. sprom->country_code = tuple->data[1];
  482. break;
  483. case SSB_SDIO_CIS_ANTENNA:
  484. GOTO_ERROR_ON(tuple->size != 2,
  485. "ant tpl size");
  486. sprom->ant_available_a = tuple->data[1];
  487. sprom->ant_available_bg = tuple->data[1];
  488. break;
  489. case SSB_SDIO_CIS_ANTGAIN:
  490. GOTO_ERROR_ON(tuple->size != 2,
  491. "antg tpl size");
  492. sprom->antenna_gain.a0 = tuple->data[1];
  493. sprom->antenna_gain.a1 = tuple->data[1];
  494. sprom->antenna_gain.a2 = tuple->data[1];
  495. sprom->antenna_gain.a3 = tuple->data[1];
  496. break;
  497. case SSB_SDIO_CIS_BFLAGS:
  498. GOTO_ERROR_ON((tuple->size != 3) &&
  499. (tuple->size != 5),
  500. "bfl tpl size");
  501. sprom->boardflags_lo = tuple->data[1] |
  502. ((u16)tuple->data[2] << 8);
  503. break;
  504. case SSB_SDIO_CIS_LEDS:
  505. GOTO_ERROR_ON(tuple->size != 5,
  506. "leds tpl size");
  507. sprom->gpio0 = tuple->data[1];
  508. sprom->gpio1 = tuple->data[2];
  509. sprom->gpio2 = tuple->data[3];
  510. sprom->gpio3 = tuple->data[4];
  511. break;
  512. default:
  513. break;
  514. }
  515. break;
  516. default:
  517. break;
  518. }
  519. tuple = tuple->next;
  520. }
  521. return 0;
  522. error:
  523. dev_err(ssb_sdio_dev(bus), "failed to fetch device invariants: %s\n",
  524. error_description);
  525. return -ENODEV;
  526. }
  527. void ssb_sdio_exit(struct ssb_bus *bus)
  528. {
  529. if (bus->bustype != SSB_BUSTYPE_SDIO)
  530. return;
  531. /* Nothing to do here. */
  532. }
  533. int ssb_sdio_init(struct ssb_bus *bus)
  534. {
  535. if (bus->bustype != SSB_BUSTYPE_SDIO)
  536. return 0;
  537. bus->sdio_sbaddr = ~0;
  538. return 0;
  539. }