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; }
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_probe(const struct hwbus_ops *hwbus_ops, struct hwbus_priv *hwbus, struct device *pdev, struct cw1200_common **core, int ref_clk, const u8 *macaddr, const char *sdd_path, bool have_5ghz) { int err = -EINVAL; struct ieee80211_hw *dev; struct cw1200_common *priv; struct wsm_operational_mode mode = { .power_mode = cw1200_power_mode, .disable_more_flag_usage = true, }; dev = cw1200_init_common(macaddr, have_5ghz); if (!dev) goto err; priv = dev->priv; priv->hw_refclk = ref_clk; if (cw1200_refclk) priv->hw_refclk = cw1200_refclk; priv->sdd_path = (char *)sdd_path; if (cw1200_sdd_path) priv->sdd_path = cw1200_sdd_path; priv->hwbus_ops = hwbus_ops; priv->hwbus_priv = hwbus; priv->pdev = pdev; SET_IEEE80211_DEV(priv->hw, pdev); /* Pass struct cw1200_common back up */ *core = priv; err = cw1200_register_bh(priv); if (err) goto err1; err = cw1200_load_firmware(priv); if (err) goto err2; if (wait_event_interruptible_timeout(priv->wsm_startup_done, priv->firmware_ready, 3*HZ) <= 0) { /* TODO: Need to find how to reset device in QUEUE mode properly. */ pr_err("Timeout waiting on device startup\n"); err = -ETIMEDOUT; goto err2; } /* Set low-power mode. */ wsm_set_operational_mode(priv, &mode); /* Enable multi-TX confirmation */ wsm_use_multi_tx_conf(priv, true); err = cw1200_register_common(dev); if (err) goto err2; return err; err2: cw1200_unregister_bh(priv); err1: cw1200_free_common(dev); err: *core = NULL; return err; } EXPORT_SYMBOL_GPL(cw1200_core_probe); void cw1200_core_release(struct cw1200_common *self) { /* Disable device interrupts */ self->hwbus_ops->lock(self->hwbus_priv); __cw1200_irq_enable(self, 0); self->hwbus_ops->unlock(self->hwbus_priv); /* And then clean up */ cw1200_unregister_common(self->hw); cw1200_free_common(self->hw); return; }