]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - packages/devs/spi/arm/mxc/v2_0/src/mxc_spi.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / devs / spi / arm / mxc / v2_0 / src / mxc_spi.c
index d7957aa4ca795d48ba61ed1c38a2df1c1f9f9853..c7716b6928f67fcd14d8071d086540f77d3014f6 100644 (file)
@@ -75,45 +75,23 @@ void clock_spi_enable(unsigned int spi_clk);
 const unsigned int baud_rate_div[] = {
     4, 8, 16, 32, 64, 128, 256, 512,
 };
-
+static int version = 1;
 #elif defined(MXC_SPI_VER_XX)
 const unsigned int baud_rate_div[] = {
     3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512,
 };
-
+static int version = 2;
+#elif defined(MXC_SPI_VER_2_3)
+const unsigned int baud_rate_div[] = {
+    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+};
+static int version = 3;
 #else
 #error No SPI version defined
 #endif
 
 const int BAUD_RATE_DIV_MAX = sizeof(baud_rate_div) / sizeof(unsigned int);
 
-/*!
- * It is for the master mode operation to exchange a single word with
- * external device.
- *
- * @param   data        data to be transferred
- * @param   base        base address of the spi module
- *
- * @return              the value received from the Rx register
- */
-unsigned int spi_xchg_single(unsigned int data, unsigned int base)
-{
-    volatile unsigned int cfg_reg = readl(base + SPI_CTRL_REG_OFF);
-
-    hal_delay_us(100);
-
-    writel(data, base + SPI_TX_REG_OFF);
-
-    cfg_reg |= SPI_CTRL_REG_XCH_BIT;
-
-    writel(cfg_reg, base + SPI_CTRL_REG_OFF);
-
-    while ((readl(base + SPI_INT_STAT_REG_OFF) & SPI_INT_STAT_RR) == 0) {
-    }
-
-    return readl(base + SPI_RX_REG_OFF);
-}
-
 /*!
  * Initialize and enable a spi module
  *
@@ -145,7 +123,7 @@ int spi_init(unsigned int base, unsigned int baud, unsigned int ctrl_val)
     }
 
     // to adjust for differen spi versions
-    if (BAUD_RATE_DIV_MAX > 8) {
+    if (version == 2) {
         ctrl_val |= ((i + 1) << SPI_CTRL_REG_RATE_SH);
     } else
         ctrl_val |= (i << SPI_CTRL_REG_RATE_SH);
@@ -154,6 +132,8 @@ int spi_init(unsigned int base, unsigned int baud, unsigned int ctrl_val)
     diag_printf1("ctrl_val=0x%x, i=%d, SPI_CTRL_REG_RATE_SH=%d\n",
                 ctrl_val, i, SPI_CTRL_REG_RATE_SH);
 
+    /* Reinitialize the control register */
+    writel(0, base + SPI_CTRL_REG_OFF);
     writel(SPI_CTRL_EN, base + SPI_CTRL_REG_OFF);
 
     writel(ctrl_val, base + SPI_CTRL_REG_OFF);
@@ -166,20 +146,67 @@ int spi_init(unsigned int base, unsigned int baud, unsigned int ctrl_val)
 }
 
 #ifdef PMIC_SPI_BASE
+/*!
+ * It is for the master mode operation to exchange a single word with
+ * external device.
+ *
+ * @param   data        data to be transferred
+ * @param   base        base address of the spi module
+ *
+ * @return              the value received from the Rx register
+ */
+unsigned int spi_xchg_single(unsigned int data, unsigned int base)
+{
+    volatile unsigned int cfg_reg = readl(base + SPI_CTRL_REG_OFF);
+
+#if defined(MXC_SPI_VER_2_3)
+    int ss_num = (PMIC_SPI_CHIP_SELECT_NO >> 18) & 0x3;
+    volatile unsigned int pol_reg = readl(base + SPI_CONFIG_REG_OFF);
+    pol_reg &= ~(1 << (12 + ss_num));
+    /* Activate the SS signal */
+    pol_reg |= PMIC_SPI_SS_POL;
+    writel(pol_reg, base + SPI_CONFIG_REG_OFF);
+#endif
+
+    hal_delay_us(100);
+
+    writel(data, base + SPI_TX_REG_OFF);
+
+    cfg_reg |= SPI_CTRL_REG_XCH_BIT;
+
+    writel(cfg_reg, base + SPI_CTRL_REG_OFF);
+
+    while ((readl(base + SPI_INT_STAT_REG_OFF) & SPI_INT_STAT_RR) == 0) {
+    }
+
+#if defined(MXC_SPI_VER_2_3)
+    pol_reg &= ~(1 << (12 + ss_num));
+    pol_reg |= (~PMIC_SPI_SS_POL) & (1 << (12 + ss_num));
+    /* Deactivate the SS signal */
+    writel(PMIC_SPI_SS_POL, base + SPI_CONFIG_REG_OFF);
+#endif
+
+    return readl(base + SPI_RX_REG_OFF);
+}
+
 static void mxc_pmic_init(void)
 {
-       volatile unsigned int rev_id;
+    volatile unsigned int rev_id;
+    unsigned int ctrl;
 
-    spi_init(PMIC_SPI_BASE, 4000000,      // 4MHz data rate
-             SPI_CTRL_REG_BIT_COUNT32 |
-             SPI_CTRL_CS0 |
-             SPI_CTRL_SSPOL_HIGH |
-             SPI_CTRL_MODE_MASTER |
-             SPI_CTRL_EN
-             );
+#if defined(MXC_SPI_VER_2_3)
+    ctrl = SPI_CTRL_REG_BIT_COUNT32 | SPI_CTRL_MODE_MASTER_0 | SPI_CTRL_EN;
+#else
+    ctrl = SPI_CTRL_REG_BIT_COUNT32 | SPI_CTRL_SSPOL_HIGH |
+           SPI_CTRL_MODE_MASTER | SPI_CTRL_EN;
+#endif
+    /* Activate the SS signal */
+    ctrl |= PMIC_SPI_CHIP_SELECT_NO;
+    spi_init(PMIC_SPI_BASE, 6000000,      // 4MHz data rate
+             ctrl);
 
     rev_id = pmic_reg(7, 0, 0);
-       diag_printf("PMIC ID: 0x%08x [Rev: ", rev_id);
+    diag_printf("PMIC ID: 0x%08x [Rev: ", rev_id);
     switch (rev_id & 0x1F) {
     case 0x1:
         diag_printf("1.0");
@@ -289,3 +316,147 @@ unsigned int pmic_reg(unsigned int reg, unsigned int val, unsigned int write)
     return temp;
 }
 #endif // PMIC_SPI_BASE
+
+#ifdef CPLD_SPI_BASE
+
+unsigned int spi_cpld_xchg_single(unsigned int data, unsigned int data1, unsigned int base)
+{
+    volatile unsigned int cfg_reg = readl(base + SPI_CTRL_REG_OFF);
+    unsigned int temp;
+
+    /* Activate the SS signal */
+    cfg_reg |= CPLD_SPI_CHIP_SELECT_NO;
+    writel(cfg_reg, CPLD_SPI_BASE + SPI_CTRL_REG_OFF);
+
+    /* Write the data */
+    writel(data, base + SPI_TX_REG_OFF);
+    writel(data1, base + SPI_TX_REG_OFF);
+
+    cfg_reg |= SPI_CTRL_REG_XCH_BIT;
+    writel(cfg_reg, base + SPI_CTRL_REG_OFF);
+
+    while ((((cfg_reg = readl(base + SPI_TEST_REG_OFF)) &
+              SPI_TEST_REG_RXCNT_MASK) >> SPI_TEST_REG_RXCNT_OFFSET) != 2) {
+    }
+
+    /* Deactivate the SS signal */
+    cfg_reg = readl(base + SPI_CTRL_REG_OFF);
+    cfg_reg &= ~SPI_CTRL_CS_MASK;
+    writel(cfg_reg, base + SPI_CTRL_REG_OFF);
+
+    /* Read from RX FIFO, second entry contains the data */
+    temp = readl(base + SPI_RX_REG_OFF);
+    temp = readl(base + SPI_RX_REG_OFF);
+    return ((temp >> 6) & 0xffff);
+}
+
+static void mxc_cpld_spi_init(void)
+{
+    unsigned int ctrl;
+
+    ctrl = SPI_CTRL_REG_BIT_COUNT46 | CPLD_SPI_CTRL_MODE_MASTER | SPI_CTRL_EN;
+
+    spi_init(CPLD_SPI_BASE, 18000000,      // 54MHz data rate
+             ctrl);
+}
+
+RedBoot_init(mxc_cpld_spi_init, RedBoot_INIT_PRIO(102));
+
+static void do_cpld(int argc, char *argv[]);
+
+RedBoot_cmd("spi_cpld",
+            "Read/Write 16-bit internal CPLD register over CSPI",
+            "<reg num> [16-bit value to be written]",
+            do_cpld
+           );
+
+static void do_cpld(int argc,char *argv[])
+{
+    unsigned int reg, temp, val = 0, read = 1;
+
+    if (argc == 1) {
+        diag_printf("\tRead:  spi_cpld <reg num>\n");
+        diag_printf("\tWrite: spi_cpld <reg num> <value to be written>\n");
+        return;
+    }
+
+    if (!parse_num(*(&argv[1]), (unsigned long *)&reg, &argv[1], ":")) {
+        diag_printf("Error: Invalid parameter\n");
+        return;
+    }
+
+    if (argc == 3) {
+        if (!parse_num(*(&argv[2]), (unsigned long *)&val, &argv[2], ":")) {
+            diag_printf("Error: Invalid parameter\n");
+            return;
+        }
+        read = 0;
+    }
+
+    temp = cpld_reg(reg, val, read);
+
+    diag_printf("\tval: 0x%04x\n\n", temp);
+}
+
+/*!
+ * To read/write to a CPLD register.
+ *
+ * @param   reg         register number inside the CPLD
+ * @param   val         data to be written to the register; don't care for read
+ * @param   read        0 for write; 1 for read
+ *
+ * @return              the actual data in the CPLD register
+ */
+unsigned int cpld_reg_xfer(unsigned int reg, unsigned int val, unsigned int read)
+{
+    unsigned int local_val1, local_val2;
+
+    reg >>= 1;
+
+    local_val1 = (read << 13) | ((reg & 0x0001FFFF) >> 5) | 0x00001000;
+    if (read) {
+        //local_val1 = (read << 22) | (reg << 4) | 0x00200004;
+        //local_val2 = 0x1F;
+        local_val2 = ( ((reg & 0x0000001F) << 27) | 0x0200001f);
+
+    } else {
+        //local_val1 = (read << 22) | (reg << 4) | 0x00200007;
+        //local_val2 = ((val & 0xFFFF) << 6) | 0x00400027;
+        local_val2 = ( ((reg & 0x0000001F) << 27) | ((val & 0x0000FFFF) << 6) | 0x03C00027);
+
+    }
+
+    diag_printf1("reg=0x%x, val=0x%08x\n", reg, val);
+    return spi_cpld_xchg_single(local_val1, local_val2, CPLD_SPI_BASE);
+}
+
+/*!
+ * To read/write to a CPLD register. For write, it does another read for the
+ * actual register value.
+ *
+ * @param   reg         register number inside the CPLD
+ * @param   val         data to be written to the register; don't care for read
+ * @param   read        0 for write; 1 for read
+ *
+ * @return              the actual data in the CPLD register
+ */
+unsigned int cpld_reg(unsigned int reg, unsigned int val, unsigned int read)
+{
+    unsigned int temp;
+
+    if (reg > 0x20068 || read > 1 ) {
+        diag_printf("<reg num> = %x is invalid. Should be less then 0x20068\n", reg);
+        return 0;
+    }
+
+    temp = cpld_reg_xfer(reg, val, read);
+    diag_printf1("reg=0x%x, val=0x%08x\n", reg, val);
+
+    if (read == 0) {
+        temp = cpld_reg_xfer(reg, val, 1);
+    }
+
+    return temp;
+}
+
+#endif // CPLD_SPI_BASE