832 lines · c
1/*2 * Sonics Silicon Backplane3 * PCMCIA-Hostbus related functions4 *5 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>6 * Copyright 2007-2008 Michael Buesch <m@bues.ch>7 *8 * Licensed under the GNU/GPL. See COPYING for details.9 */10 11#include "ssb_private.h"12 13#include <linux/ssb/ssb.h>14#include <linux/delay.h>15#include <linux/io.h>16#include <linux/etherdevice.h>17 18#include <pcmcia/cistpl.h>19#include <pcmcia/ciscode.h>20#include <pcmcia/ds.h>21#include <pcmcia/cisreg.h>22 23 24/* Define the following to 1 to enable a printk on each coreswitch. */25#define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 026 27 28/* PCMCIA configuration registers */29#define SSB_PCMCIA_ADDRESS0 0x2E30#define SSB_PCMCIA_ADDRESS1 0x3031#define SSB_PCMCIA_ADDRESS2 0x3232#define SSB_PCMCIA_MEMSEG 0x3433#define SSB_PCMCIA_SPROMCTL 0x3634#define SSB_PCMCIA_SPROMCTL_IDLE 035#define SSB_PCMCIA_SPROMCTL_WRITE 136#define SSB_PCMCIA_SPROMCTL_READ 237#define SSB_PCMCIA_SPROMCTL_WRITEEN 438#define SSB_PCMCIA_SPROMCTL_WRITEDIS 739#define SSB_PCMCIA_SPROMCTL_DONE 840#define SSB_PCMCIA_SPROM_DATALO 0x3841#define SSB_PCMCIA_SPROM_DATAHI 0x3A42#define SSB_PCMCIA_SPROM_ADDRLO 0x3C43#define SSB_PCMCIA_SPROM_ADDRHI 0x3E44 45/* Hardware invariants CIS tuples */46#define SSB_PCMCIA_CIS 0x8047#define SSB_PCMCIA_CIS_ID 0x0148#define SSB_PCMCIA_CIS_BOARDREV 0x0249#define SSB_PCMCIA_CIS_PA 0x0350#define SSB_PCMCIA_CIS_PA_PA0B0_LO 051#define SSB_PCMCIA_CIS_PA_PA0B0_HI 152#define SSB_PCMCIA_CIS_PA_PA0B1_LO 253#define SSB_PCMCIA_CIS_PA_PA0B1_HI 354#define SSB_PCMCIA_CIS_PA_PA0B2_LO 455#define SSB_PCMCIA_CIS_PA_PA0B2_HI 556#define SSB_PCMCIA_CIS_PA_ITSSI 657#define SSB_PCMCIA_CIS_PA_MAXPOW 758#define SSB_PCMCIA_CIS_OEMNAME 0x0459#define SSB_PCMCIA_CIS_CCODE 0x0560#define SSB_PCMCIA_CIS_ANTENNA 0x0661#define SSB_PCMCIA_CIS_ANTGAIN 0x0762#define SSB_PCMCIA_CIS_BFLAGS 0x0863#define SSB_PCMCIA_CIS_LEDS 0x0964 65/* PCMCIA SPROM size. */66#define SSB_PCMCIA_SPROM_SIZE 25667#define SSB_PCMCIA_SPROM_SIZE_BYTES (SSB_PCMCIA_SPROM_SIZE * sizeof(u16))68 69 70/* Write to a PCMCIA configuration register. */71static int ssb_pcmcia_cfg_write(struct ssb_bus *bus, u8 offset, u8 value)72{73 int res;74 75 res = pcmcia_write_config_byte(bus->host_pcmcia, offset, value);76 if (unlikely(res != 0))77 return -EBUSY;78 79 return 0;80}81 82/* Read from a PCMCIA configuration register. */83static int ssb_pcmcia_cfg_read(struct ssb_bus *bus, u8 offset, u8 *value)84{85 int res;86 87 res = pcmcia_read_config_byte(bus->host_pcmcia, offset, value);88 if (unlikely(res != 0))89 return -EBUSY;90 91 return 0;92}93 94int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,95 u8 coreidx)96{97 int err;98 int attempts = 0;99 u32 cur_core;100 u32 addr;101 u32 read_addr;102 u8 val;103 104 addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;105 while (1) {106 err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS0,107 (addr & 0x0000F000) >> 12);108 if (err)109 goto error;110 err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS1,111 (addr & 0x00FF0000) >> 16);112 if (err)113 goto error;114 err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_ADDRESS2,115 (addr & 0xFF000000) >> 24);116 if (err)117 goto error;118 119 read_addr = 0;120 121 err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS0, &val);122 if (err)123 goto error;124 read_addr |= ((u32)(val & 0x0F)) << 12;125 err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS1, &val);126 if (err)127 goto error;128 read_addr |= ((u32)val) << 16;129 err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_ADDRESS2, &val);130 if (err)131 goto error;132 read_addr |= ((u32)val) << 24;133 134 cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE;135 if (cur_core == coreidx)136 break;137 138 err = -ETIMEDOUT;139 if (attempts++ > SSB_BAR0_MAX_RETRIES)140 goto error;141 udelay(10);142 }143 144 return 0;145error:146 pr_err("Failed to switch to core %u\n", coreidx);147 return err;148}149 150static int ssb_pcmcia_switch_core(struct ssb_bus *bus, struct ssb_device *dev)151{152 int err;153 154#if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG155 pr_info("Switching to %s core, index %d\n",156 ssb_core_name(dev->id.coreid), dev->core_index);157#endif158 159 err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);160 if (!err)161 bus->mapped_device = dev;162 163 return err;164}165 166int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)167{168 int attempts = 0;169 int err;170 u8 val;171 172 WARN_ON((seg != 0) && (seg != 1));173 while (1) {174 err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_MEMSEG, seg);175 if (err)176 goto error;177 err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_MEMSEG, &val);178 if (err)179 goto error;180 if (val == seg)181 break;182 183 err = -ETIMEDOUT;184 if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES))185 goto error;186 udelay(10);187 }188 bus->mapped_pcmcia_seg = seg;189 190 return 0;191error:192 pr_err("Failed to switch pcmcia segment\n");193 return err;194}195 196static int select_core_and_segment(struct ssb_device *dev,197 u16 *offset)198{199 struct ssb_bus *bus = dev->bus;200 int err;201 u8 need_segment;202 203 if (*offset >= 0x800) {204 *offset -= 0x800;205 need_segment = 1;206 } else207 need_segment = 0;208 209 if (unlikely(dev != bus->mapped_device)) {210 err = ssb_pcmcia_switch_core(bus, dev);211 if (unlikely(err))212 return err;213 }214 if (unlikely(need_segment != bus->mapped_pcmcia_seg)) {215 err = ssb_pcmcia_switch_segment(bus, need_segment);216 if (unlikely(err))217 return err;218 }219 220 return 0;221}222 223static u8 ssb_pcmcia_read8(struct ssb_device *dev, u16 offset)224{225 struct ssb_bus *bus = dev->bus;226 unsigned long flags;227 int err;228 u8 value = 0xFF;229 230 spin_lock_irqsave(&bus->bar_lock, flags);231 err = select_core_and_segment(dev, &offset);232 if (likely(!err))233 value = readb(bus->mmio + offset);234 spin_unlock_irqrestore(&bus->bar_lock, flags);235 236 return value;237}238 239static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)240{241 struct ssb_bus *bus = dev->bus;242 unsigned long flags;243 int err;244 u16 value = 0xFFFF;245 246 spin_lock_irqsave(&bus->bar_lock, flags);247 err = select_core_and_segment(dev, &offset);248 if (likely(!err))249 value = readw(bus->mmio + offset);250 spin_unlock_irqrestore(&bus->bar_lock, flags);251 252 return value;253}254 255static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)256{257 struct ssb_bus *bus = dev->bus;258 unsigned long flags;259 int err;260 u32 lo = 0xFFFFFFFF, hi = 0xFFFFFFFF;261 262 spin_lock_irqsave(&bus->bar_lock, flags);263 err = select_core_and_segment(dev, &offset);264 if (likely(!err)) {265 lo = readw(bus->mmio + offset);266 hi = readw(bus->mmio + offset + 2);267 }268 spin_unlock_irqrestore(&bus->bar_lock, flags);269 270 return (lo | (hi << 16));271}272 273#ifdef CONFIG_SSB_BLOCKIO274static void ssb_pcmcia_block_read(struct ssb_device *dev, void *buffer,275 size_t count, u16 offset, u8 reg_width)276{277 struct ssb_bus *bus = dev->bus;278 unsigned long flags;279 void __iomem *addr = bus->mmio + offset;280 int err;281 282 spin_lock_irqsave(&bus->bar_lock, flags);283 err = select_core_and_segment(dev, &offset);284 if (unlikely(err)) {285 memset(buffer, 0xFF, count);286 goto unlock;287 }288 switch (reg_width) {289 case sizeof(u8): {290 u8 *buf = buffer;291 292 while (count) {293 *buf = __raw_readb(addr);294 buf++;295 count--;296 }297 break;298 }299 case sizeof(u16): {300 __le16 *buf = buffer;301 302 WARN_ON(count & 1);303 while (count) {304 *buf = (__force __le16)__raw_readw(addr);305 buf++;306 count -= 2;307 }308 break;309 }310 case sizeof(u32): {311 __le16 *buf = buffer;312 313 WARN_ON(count & 3);314 while (count) {315 *buf = (__force __le16)__raw_readw(addr);316 buf++;317 *buf = (__force __le16)__raw_readw(addr + 2);318 buf++;319 count -= 4;320 }321 break;322 }323 default:324 WARN_ON(1);325 }326unlock:327 spin_unlock_irqrestore(&bus->bar_lock, flags);328}329#endif /* CONFIG_SSB_BLOCKIO */330 331static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value)332{333 struct ssb_bus *bus = dev->bus;334 unsigned long flags;335 int err;336 337 spin_lock_irqsave(&bus->bar_lock, flags);338 err = select_core_and_segment(dev, &offset);339 if (likely(!err))340 writeb(value, bus->mmio + offset);341 spin_unlock_irqrestore(&bus->bar_lock, flags);342}343 344static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)345{346 struct ssb_bus *bus = dev->bus;347 unsigned long flags;348 int err;349 350 spin_lock_irqsave(&bus->bar_lock, flags);351 err = select_core_and_segment(dev, &offset);352 if (likely(!err))353 writew(value, bus->mmio + offset);354 spin_unlock_irqrestore(&bus->bar_lock, flags);355}356 357static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)358{359 struct ssb_bus *bus = dev->bus;360 unsigned long flags;361 int err;362 363 spin_lock_irqsave(&bus->bar_lock, flags);364 err = select_core_and_segment(dev, &offset);365 if (likely(!err)) {366 writew((value & 0x0000FFFF), bus->mmio + offset);367 writew(((value & 0xFFFF0000) >> 16), bus->mmio + offset + 2);368 }369 spin_unlock_irqrestore(&bus->bar_lock, flags);370}371 372#ifdef CONFIG_SSB_BLOCKIO373static void ssb_pcmcia_block_write(struct ssb_device *dev, const void *buffer,374 size_t count, u16 offset, u8 reg_width)375{376 struct ssb_bus *bus = dev->bus;377 unsigned long flags;378 void __iomem *addr = bus->mmio + offset;379 int err;380 381 spin_lock_irqsave(&bus->bar_lock, flags);382 err = select_core_and_segment(dev, &offset);383 if (unlikely(err))384 goto unlock;385 switch (reg_width) {386 case sizeof(u8): {387 const u8 *buf = buffer;388 389 while (count) {390 __raw_writeb(*buf, addr);391 buf++;392 count--;393 }394 break;395 }396 case sizeof(u16): {397 const __le16 *buf = buffer;398 399 WARN_ON(count & 1);400 while (count) {401 __raw_writew((__force u16)(*buf), addr);402 buf++;403 count -= 2;404 }405 break;406 }407 case sizeof(u32): {408 const __le16 *buf = buffer;409 410 WARN_ON(count & 3);411 while (count) {412 __raw_writew((__force u16)(*buf), addr);413 buf++;414 __raw_writew((__force u16)(*buf), addr + 2);415 buf++;416 count -= 4;417 }418 break;419 }420 default:421 WARN_ON(1);422 }423unlock:424 spin_unlock_irqrestore(&bus->bar_lock, flags);425}426#endif /* CONFIG_SSB_BLOCKIO */427 428/* Not "static", as it's used in main.c */429const struct ssb_bus_ops ssb_pcmcia_ops = {430 .read8 = ssb_pcmcia_read8,431 .read16 = ssb_pcmcia_read16,432 .read32 = ssb_pcmcia_read32,433 .write8 = ssb_pcmcia_write8,434 .write16 = ssb_pcmcia_write16,435 .write32 = ssb_pcmcia_write32,436#ifdef CONFIG_SSB_BLOCKIO437 .block_read = ssb_pcmcia_block_read,438 .block_write = ssb_pcmcia_block_write,439#endif440};441 442static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command)443{444 unsigned int i;445 int err;446 u8 value;447 448 err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROMCTL, command);449 if (err)450 return err;451 for (i = 0; i < 1000; i++) {452 err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROMCTL, &value);453 if (err)454 return err;455 if (value & SSB_PCMCIA_SPROMCTL_DONE)456 return 0;457 udelay(10);458 }459 460 return -ETIMEDOUT;461}462 463/* offset is the 16bit word offset */464static int ssb_pcmcia_sprom_read(struct ssb_bus *bus, u16 offset, u16 *value)465{466 int err;467 u8 lo, hi;468 469 offset *= 2; /* Make byte offset */470 471 err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRLO,472 (offset & 0x00FF));473 if (err)474 return err;475 err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRHI,476 (offset & 0xFF00) >> 8);477 if (err)478 return err;479 err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_READ);480 if (err)481 return err;482 err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROM_DATALO, &lo);483 if (err)484 return err;485 err = ssb_pcmcia_cfg_read(bus, SSB_PCMCIA_SPROM_DATAHI, &hi);486 if (err)487 return err;488 *value = (lo | (((u16)hi) << 8));489 490 return 0;491}492 493/* offset is the 16bit word offset */494static int ssb_pcmcia_sprom_write(struct ssb_bus *bus, u16 offset, u16 value)495{496 int err;497 498 offset *= 2; /* Make byte offset */499 500 err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRLO,501 (offset & 0x00FF));502 if (err)503 return err;504 err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_ADDRHI,505 (offset & 0xFF00) >> 8);506 if (err)507 return err;508 err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_DATALO,509 (value & 0x00FF));510 if (err)511 return err;512 err = ssb_pcmcia_cfg_write(bus, SSB_PCMCIA_SPROM_DATAHI,513 (value & 0xFF00) >> 8);514 if (err)515 return err;516 err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITE);517 if (err)518 return err;519 msleep(20);520 521 return 0;522}523 524/* Read the SPROM image. bufsize is in 16bit words. */525static int ssb_pcmcia_sprom_read_all(struct ssb_bus *bus, u16 *sprom)526{527 int err, i;528 529 for (i = 0; i < SSB_PCMCIA_SPROM_SIZE; i++) {530 err = ssb_pcmcia_sprom_read(bus, i, &sprom[i]);531 if (err)532 return err;533 }534 535 return 0;536}537 538/* Write the SPROM image. size is in 16bit words. */539static int ssb_pcmcia_sprom_write_all(struct ssb_bus *bus, const u16 *sprom)540{541 int i, err;542 bool failed = 0;543 size_t size = SSB_PCMCIA_SPROM_SIZE;544 545 pr_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");546 err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEEN);547 if (err) {548 pr_notice("Could not enable SPROM write access\n");549 return -EBUSY;550 }551 pr_notice("[ 0%%");552 msleep(500);553 for (i = 0; i < size; i++) {554 if (i == size / 4)555 pr_cont("25%%");556 else if (i == size / 2)557 pr_cont("50%%");558 else if (i == (size * 3) / 4)559 pr_cont("75%%");560 else if (i % 2)561 pr_cont(".");562 err = ssb_pcmcia_sprom_write(bus, i, sprom[i]);563 if (err) {564 pr_notice("Failed to write to SPROM\n");565 failed = 1;566 break;567 }568 }569 err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEDIS);570 if (err) {571 pr_notice("Could not disable SPROM write access\n");572 failed = 1;573 }574 msleep(500);575 if (!failed) {576 pr_cont("100%% ]\n");577 pr_notice("SPROM written\n");578 }579 580 return failed ? -EBUSY : 0;581}582 583static int ssb_pcmcia_sprom_check_crc(const u16 *sprom, size_t size)584{585 //TODO586 return 0;587}588 589#define GOTO_ERROR_ON(condition, description) do { \590 if (unlikely(condition)) { \591 error_description = description; \592 goto error; \593 } \594 } while (0)595 596static int ssb_pcmcia_get_mac(struct pcmcia_device *p_dev,597 tuple_t *tuple,598 void *priv)599{600 struct ssb_sprom *sprom = priv;601 602 if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)603 return -EINVAL;604 if (tuple->TupleDataLen != ETH_ALEN + 2)605 return -EINVAL;606 if (tuple->TupleData[1] != ETH_ALEN)607 return -EINVAL;608 memcpy(sprom->il0mac, &tuple->TupleData[2], ETH_ALEN);609 return 0;610};611 612static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,613 tuple_t *tuple,614 void *priv)615{616 struct ssb_init_invariants *iv = priv;617 struct ssb_sprom *sprom = &iv->sprom;618 struct ssb_boardinfo *bi = &iv->boardinfo;619 const char *error_description;620 621 GOTO_ERROR_ON(tuple->TupleDataLen < 1, "VEN tpl < 1");622 switch (tuple->TupleData[0]) {623 case SSB_PCMCIA_CIS_ID:624 GOTO_ERROR_ON((tuple->TupleDataLen != 5) &&625 (tuple->TupleDataLen != 7),626 "id tpl size");627 bi->vendor = tuple->TupleData[1] |628 ((u16)tuple->TupleData[2] << 8);629 break;630 case SSB_PCMCIA_CIS_BOARDREV:631 GOTO_ERROR_ON(tuple->TupleDataLen != 2,632 "boardrev tpl size");633 sprom->board_rev = tuple->TupleData[1];634 break;635 case SSB_PCMCIA_CIS_PA:636 GOTO_ERROR_ON((tuple->TupleDataLen != 9) &&637 (tuple->TupleDataLen != 10),638 "pa tpl size");639 sprom->pa0b0 = tuple->TupleData[1] |640 ((u16)tuple->TupleData[2] << 8);641 sprom->pa0b1 = tuple->TupleData[3] |642 ((u16)tuple->TupleData[4] << 8);643 sprom->pa0b2 = tuple->TupleData[5] |644 ((u16)tuple->TupleData[6] << 8);645 sprom->itssi_a = tuple->TupleData[7];646 sprom->itssi_bg = tuple->TupleData[7];647 sprom->maxpwr_a = tuple->TupleData[8];648 sprom->maxpwr_bg = tuple->TupleData[8];649 break;650 case SSB_PCMCIA_CIS_OEMNAME:651 /* We ignore this. */652 break;653 case SSB_PCMCIA_CIS_CCODE:654 GOTO_ERROR_ON(tuple->TupleDataLen != 2,655 "ccode tpl size");656 sprom->country_code = tuple->TupleData[1];657 break;658 case SSB_PCMCIA_CIS_ANTENNA:659 GOTO_ERROR_ON(tuple->TupleDataLen != 2,660 "ant tpl size");661 sprom->ant_available_a = tuple->TupleData[1];662 sprom->ant_available_bg = tuple->TupleData[1];663 break;664 case SSB_PCMCIA_CIS_ANTGAIN:665 GOTO_ERROR_ON(tuple->TupleDataLen != 2,666 "antg tpl size");667 sprom->antenna_gain.a0 = tuple->TupleData[1];668 sprom->antenna_gain.a1 = tuple->TupleData[1];669 sprom->antenna_gain.a2 = tuple->TupleData[1];670 sprom->antenna_gain.a3 = tuple->TupleData[1];671 break;672 case SSB_PCMCIA_CIS_BFLAGS:673 GOTO_ERROR_ON((tuple->TupleDataLen != 3) &&674 (tuple->TupleDataLen != 5),675 "bfl tpl size");676 sprom->boardflags_lo = tuple->TupleData[1] |677 ((u16)tuple->TupleData[2] << 8);678 break;679 case SSB_PCMCIA_CIS_LEDS:680 GOTO_ERROR_ON(tuple->TupleDataLen != 5,681 "leds tpl size");682 sprom->gpio0 = tuple->TupleData[1];683 sprom->gpio1 = tuple->TupleData[2];684 sprom->gpio2 = tuple->TupleData[3];685 sprom->gpio3 = tuple->TupleData[4];686 break;687 }688 return -ENOSPC; /* continue with next entry */689 690error:691 pr_err("PCMCIA: Failed to fetch device invariants: %s\n",692 error_description);693 return -ENODEV;694}695 696 697int ssb_pcmcia_get_invariants(struct ssb_bus *bus,698 struct ssb_init_invariants *iv)699{700 struct ssb_sprom *sprom = &iv->sprom;701 int res;702 703 memset(sprom, 0xFF, sizeof(*sprom));704 sprom->revision = 1;705 sprom->boardflags_lo = 0;706 sprom->boardflags_hi = 0;707 708 /* First fetch the MAC address. */709 res = pcmcia_loop_tuple(bus->host_pcmcia, CISTPL_FUNCE,710 ssb_pcmcia_get_mac, sprom);711 if (res != 0) {712 pr_err("PCMCIA: Failed to fetch MAC address\n");713 return -ENODEV;714 }715 716 /* Fetch the vendor specific tuples. */717 res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS,718 ssb_pcmcia_do_get_invariants, iv);719 if ((res == 0) || (res == -ENOSPC))720 return 0;721 722 pr_err("PCMCIA: Failed to fetch device invariants\n");723 return -ENODEV;724}725 726static ssize_t ssb_sprom_show(struct device *pcmciadev,727 struct device_attribute *attr,728 char *buf)729{730 struct pcmcia_device *pdev =731 container_of(pcmciadev, struct pcmcia_device, dev);732 struct ssb_bus *bus;733 734 bus = ssb_pcmcia_dev_to_bus(pdev);735 if (!bus)736 return -ENODEV;737 738 return ssb_attr_sprom_show(bus, buf,739 ssb_pcmcia_sprom_read_all);740}741 742static ssize_t ssb_sprom_store(struct device *pcmciadev,743 struct device_attribute *attr,744 const char *buf, size_t count)745{746 struct pcmcia_device *pdev =747 container_of(pcmciadev, struct pcmcia_device, dev);748 struct ssb_bus *bus;749 750 bus = ssb_pcmcia_dev_to_bus(pdev);751 if (!bus)752 return -ENODEV;753 754 return ssb_attr_sprom_store(bus, buf, count,755 ssb_pcmcia_sprom_check_crc,756 ssb_pcmcia_sprom_write_all);757}758 759static DEVICE_ATTR_ADMIN_RW(ssb_sprom);760 761static int ssb_pcmcia_cor_setup(struct ssb_bus *bus, u8 cor)762{763 u8 val;764 int err;765 766 err = ssb_pcmcia_cfg_read(bus, cor, &val);767 if (err)768 return err;769 val &= ~COR_SOFT_RESET;770 val |= COR_FUNC_ENA | COR_IREQ_ENA | COR_LEVEL_REQ;771 err = ssb_pcmcia_cfg_write(bus, cor, val);772 if (err)773 return err;774 msleep(40);775 776 return 0;777}778 779/* Initialize the PCMCIA hardware. This is called on Init and Resume. */780int ssb_pcmcia_hardware_setup(struct ssb_bus *bus)781{782 int err;783 784 if (bus->bustype != SSB_BUSTYPE_PCMCIA)785 return 0;786 787 /* Switch segment to a known state and sync788 * bus->mapped_pcmcia_seg with hardware state. */789 ssb_pcmcia_switch_segment(bus, 0);790 /* Init the COR register. */791 err = ssb_pcmcia_cor_setup(bus, CISREG_COR);792 if (err)793 return err;794 /* Some cards also need this register to get poked. */795 err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80);796 if (err)797 return err;798 799 return 0;800}801 802void ssb_pcmcia_exit(struct ssb_bus *bus)803{804 if (bus->bustype != SSB_BUSTYPE_PCMCIA)805 return;806 807 device_remove_file(&bus->host_pcmcia->dev, &dev_attr_ssb_sprom);808}809 810int ssb_pcmcia_init(struct ssb_bus *bus)811{812 int err;813 814 if (bus->bustype != SSB_BUSTYPE_PCMCIA)815 return 0;816 817 err = ssb_pcmcia_hardware_setup(bus);818 if (err)819 goto error;820 821 bus->sprom_size = SSB_PCMCIA_SPROM_SIZE;822 mutex_init(&bus->sprom_mutex);823 err = device_create_file(&bus->host_pcmcia->dev, &dev_attr_ssb_sprom);824 if (err)825 goto error;826 827 return 0;828error:829 pr_err("Failed to initialize PCMCIA host device\n");830 return err;831}832