int cw1200_core_probe(const struct sbus_ops *sbus_ops, struct sbus_priv *sbus, struct device *pdev, struct cw1200_common **pself, u8 *mac_addr) { int err = -ENOMEM; u16 ctrl_reg; struct ieee80211_hw *dev; struct cw1200_common *priv; struct wsm_operational_mode mode = { .power_mode = wsm_power_mode_quiescent, .disableMoreFlagUsage = true, }; dev = cw1200_init_common(sizeof(struct cw1200_common), mac_addr); if (!dev) goto err; priv = dev->priv; priv->sbus_ops = sbus_ops; priv->sbus_priv = sbus; priv->pdev = pdev; SET_IEEE80211_DEV(priv->hw, pdev); /* WSM callbacks. */ priv->wsm_cbc.scan_complete = cw1200_scan_complete_cb; priv->wsm_cbc.tx_confirm = cw1200_tx_confirm_cb; priv->wsm_cbc.rx = cw1200_rx_cb; priv->wsm_cbc.suspend_resume = cw1200_suspend_resume; /* priv->wsm_cbc.set_pm_complete = cw1200_set_pm_complete_cb; */ priv->wsm_cbc.channel_switch = cw1200_channel_switch_cb; err = cw1200_register_bh(priv); if (err) goto err1; err = cw1200_load_firmware(priv); if (err) goto err2; priv->sbus_ops->lock(priv->sbus_priv); WARN_ON(priv->sbus_ops->set_block_size(priv->sbus_priv, SDIO_BLOCK_SIZE)); priv->sbus_ops->unlock(priv->sbus_priv); if (wait_event_interruptible_timeout(priv->wsm_startup_done, priv->wsm_caps.firmwareReady, 3*HZ) <= 0) { /* TODO: Needs to find how to reset device */ /* in QUEUE mode properly. */ goto err3; } WARN_ON(cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, ST90TDS_CONT_WUP_BIT)); if (cw1200_reg_read_16(priv,ST90TDS_CONTROL_REG_ID, &ctrl_reg)) WARN_ON(cw1200_reg_read_16(priv,ST90TDS_CONTROL_REG_ID, &ctrl_reg)); WARN_ON(!(ctrl_reg & ST90TDS_CONT_RDY_BIT)); /* Set low-power mode. */ WARN_ON(wsm_set_operational_mode(priv, &mode)); /* Enable multi-TX confirmation */ WARN_ON(wsm_use_multi_tx_conf(priv, true)); err = cw1200_register_common(dev); if (err) { priv->sbus_ops->irq_unsubscribe(priv->sbus_priv); goto err3; } *pself = dev->priv; return err; err3: sbus_ops->reset(sbus); err2: cw1200_unregister_bh(priv); err1: cw1200_free_common(dev); err: return err; } EXPORT_SYMBOL_GPL(cw1200_core_probe); void cw1200_core_release(struct cw1200_common *self) { cw1200_unregister_common(self->hw); cw1200_free_common(self->hw); return; }
int cw1200_core_start(struct cw1200_common *priv) { int err = -EINVAL; u16 ctrl_reg; struct wsm_operational_mode mode = { .power_mode = wsm_power_mode_quiescent, .disableMoreFlagUsage = true, }; /* Power on HW */ err = priv->sbus_ops->power_up(priv->sbus_priv); if (WARN_ON(err)) goto err1; err = cw1200_register_bh(priv); if (WARN_ON(err)) goto err2; /* Before loading fw block size has to be 512B */ priv->sbus_ops->lock(priv->sbus_priv); err = priv->sbus_ops->set_block_size(priv->sbus_priv, 512); priv->sbus_ops->unlock(priv->sbus_priv); if (err) goto err2; err = cw1200_load_firmware(priv); if (err) goto err2; /* device is up now */ atomic_set(&priv->hw_state, 1); priv->sbus_ops->lock(priv->sbus_priv); err = priv->sbus_ops->set_block_size(priv->sbus_priv, SDIO_BLOCK_SIZE); priv->sbus_ops->unlock(priv->sbus_priv); if (err) goto err2; if (wait_event_interruptible_timeout(priv->wsm_startup_done, priv->wsm_caps.firmwareReady, 3*HZ) <= 0) { /* TODO: Needs to find how to reset device */ /* in QUEUE mode properly. */ goto err2; } WARN_ON(cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, ST90TDS_CONT_WUP_BIT)); if (cw1200_reg_read_16(priv,ST90TDS_CONTROL_REG_ID, &ctrl_reg)) WARN_ON(cw1200_reg_read_16(priv,ST90TDS_CONTROL_REG_ID, &ctrl_reg)); WARN_ON(!(ctrl_reg & ST90TDS_CONT_RDY_BIT)); /* Set low-power mode. */ WARN_ON(wsm_set_operational_mode(priv, &mode)); /* Enable multi-TX confirmation */ WARN_ON(wsm_use_multi_tx_conf(priv, true)); return 0; err2: cw1200_unregister_bh(priv); atomic_set(&priv->hw_state, 0); err1: priv->sbus_ops->power_down(priv->sbus_priv); return err; } static void cw1200_common_cleanup(struct cw1200_common *priv) { tx_policy_clean(priv); /* TODO: what else ?? */ priv->wsm_rx_seq = 0; priv->wsm_tx_seq = 0; }