From 2e7866f634ddf31530c0c83ff8bdfc3b75f42e82 Mon Sep 17 00:00:00 2001
From: gdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>
Date: Sat, 30 Apr 2011 07:52:35 +0000
Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2905
 35acf78f-673a-0410-8e92-d51de3d6d3f4

---
 os/hal/platforms/STM32/sdc_lld.c | 66 ++++++++++++++++++++++++++++++++++++++++
 os/hal/platforms/STM32/sdc_lld.h | 12 ++++++++
 os/hal/src/sdc.c                 |  2 ++
 3 files changed, 80 insertions(+)

(limited to 'os')

diff --git a/os/hal/platforms/STM32/sdc_lld.c b/os/hal/platforms/STM32/sdc_lld.c
index 48f8561f9..25c7b6897 100644
--- a/os/hal/platforms/STM32/sdc_lld.c
+++ b/os/hal/platforms/STM32/sdc_lld.c
@@ -119,6 +119,72 @@ void sdc_lld_stop(SDCDriver *sdcp) {
   }
 }
 
+/**
+ * @brief   Starts the SDIO clock and sets it to init mode (400KHz or less).
+ *
+ * @param[in] sdcp      pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_start_clk(SDCDriver *sdcp) {
+
+  (void)sdcp;
+  /* Initial clock setting: 400KHz, 1bit mode.*/
+  SDIO->CLKCR  = STM32_SDIO_DIV_LS;
+  SDIO->POWER |= SDIO_POWER_PWRCTRL_0 | SDIO_POWER_PWRCTRL_1;
+  SDIO->CLKCR |= SDIO_CLKCR_CLKEN;
+}
+
+/**
+ * @brief   Sets the SDIO clock to data mode (25MHz or less).
+ *
+ * @param[in] sdcp      pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_set_data_clk(SDCDriver *sdcp) {
+
+  (void)sdcp;
+  SDIO->CLKCR = (SDIO->CLKCR & 0xFFFFFF00) | STM32_SDIO_DIV_HS;
+}
+
+/**
+ * @brief   Stops the SDIO clock.
+ *
+ * @param[in] sdcp      pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_stop_clk(SDCDriver *sdcp) {
+
+  (void)sdcp;
+  SDIO->CLKCR = 0;
+  SDIO->POWER = 0;
+}
+
+/**
+ * @brief   Switches the bus to 4 bits mode.
+ *
+ * @param[in] sdcp      pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode) {
+  uint32_t clk = SDIO->CLKCR & ~SDIO_CLKCR_WIDBUS;
+
+  (void)sdcp;
+  switch (mode) {
+  case SDC_MODE_1BIT:
+    SDIO->CLKCR = clk;
+    break;
+  case SDC_MODE_4BIT:
+    SDIO->CLKCR = clk | SDIO_CLKCR_WIDBUS_0;
+    break;
+  case SDC_MODE_8BIT:
+    SDIO->CLKCR = clk | SDIO_CLKCR_WIDBUS_1;
+  }
+}
+
 /**
  * @brief   Sends an SDIO command with no response expected.
  *
diff --git a/os/hal/platforms/STM32/sdc_lld.h b/os/hal/platforms/STM32/sdc_lld.h
index 012fdb1c7..8ed64a5b0 100644
--- a/os/hal/platforms/STM32/sdc_lld.h
+++ b/os/hal/platforms/STM32/sdc_lld.h
@@ -89,6 +89,14 @@
 /* Driver data structures and types.                                         */
 /*===========================================================================*/
 
+/**
+ * @brief   Type of SDIO bus mode.
+ */
+typedef enum {
+  SDC_MODE_1BIT = 0,
+  SDC_MODE_4BIT,
+  SDC_MODE_8BIT
+} sdcbusmode_t;
 
 /**
  * @brief   Type of a structure representing an SDC driver.
@@ -136,6 +144,10 @@ extern "C" {
   void sdc_lld_init(void);
   void sdc_lld_start(SDCDriver *sdcp);
   void sdc_lld_stop(SDCDriver *sdcp);
+  void sdc_lld_set_init_clk(SDCDriver *sdcp);
+  void sdc_lld_set_data_clk(SDCDriver *sdcp);
+  void sdc_lld_stop_clk(SDCDriver *sdcp);
+  void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode);
   void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg);
   bool_t sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
                                 uint32_t *resp);
diff --git a/os/hal/src/sdc.c b/os/hal/src/sdc.c
index 33f2b3612..701071b8b 100644
--- a/os/hal/src/sdc.c
+++ b/os/hal/src/sdc.c
@@ -135,6 +135,8 @@ bool_t sdcConnect(SDCDriver *sdcp) {
   sdcp->state = SDC_INITNG;
   chSysUnlock();
 
+  sdc_lld_start_clk(sdcp);
+
   sdcp->state = SDC_ACTIVE;
   return FALSE;
 }
-- 
cgit v1.2.3