drv_spi.c 5.7 KB
Newer Older
0
0xcccccccccccc 已提交
1
/*
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
0
0xcccccccccccc 已提交
3 4 5 6 7 8
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author                   Notes
 * 2020-10-28     0xcccccccccccc           Initial Version
马浩然 已提交
9
 * 2021-01-17     0xcccccccccccc           Bug Fixed : clock division cannot been adjusted as expected due to wrong register configuration.
0
0xcccccccccccc 已提交
10
 */
11

0
0xcccccccccccc 已提交
12 13 14 15
/**
 * @addtogroup ls2k
 */
/*@{*/
16

17 18
#include <stdlib.h>
#include <ctype.h>
19
#include <stdint.h>
20 21 22 23 24
#include <rtthread.h>
#include <drivers/spi.h>
#include "drv_spi.h"

#ifdef RT_USING_SPI
25 26 27 28
#ifdef RT_USING_SPI_GPIOCS
#include <drivers/pin.h>
#endif

0
0xcccccccccccc 已提交
29 30
static void spi_init(uint8_t spre_spr, uint8_t copl, uint8_t cpha)
{
31
    SET_SPI(SPSR, 0xc0);
0
0xcccccccccccc 已提交
32 33 34
    SET_SPI(PARAM, 0x40);
    SET_SPI(PARAM2, 0x01);
    SET_SPI(SPER, (spre_spr & 0b00001100) >> 2);
35
    SET_SPI(SPCR, 0x50 | copl << 3 | cpha << 2 | (spre_spr & 0b00000011));
0
0xcccccccccccc 已提交
36
    SET_SPI(SOFTCS, 0xff);
37 38
}

39
rt_inline void spi_set_csn(uint8_t val)
40
{
0
0xcccccccccccc 已提交
41
    SET_SPI(SOFTCS, val);
42 43
}

44
static void spi_set_cs(unsigned char cs, int new_status)
45
{
0
0xcccccccccccc 已提交
46 47
    if (cs < 4)
    {
48
        unsigned char val = 0;
0
0xcccccccccccc 已提交
49
        val = GET_SPI(SOFTCS);
50
        val |= 0x01 << cs ;     // csen=1
0
0xcccccccccccc 已提交
51 52 53 54 55 56 57 58 59 60
        if (new_status)         // cs = 1
        {
            val |= (0x10 << cs);            // csn=1
        }
        else                    // cs = 0
        {
            val &= ~(0x10 << cs);           // csn=0
        }
        SET_SPI(SOFTCS, val);
        return ;
61
    }
0
0xcccccccccccc 已提交
62 63 64
#ifdef RT_USING_SPI_GPIOCS
    else
    {
65
        rt_pin_mode(cs, PIN_MODE_OUTPUT); // with RT_USING_SPI_GPIOCS feature enabled, gpio will be used as csn pin.
0
0xcccccccccccc 已提交
66
        rt_pin_write(cs, new_status);
67
    }
0
0xcccccccccccc 已提交
68
#endif
69
}
70

71 72
static uint8_t spi_write_for_response(uint8_t data)
{
0
0xcccccccccccc 已提交
73 74 75 76 77
    uint8_t val;
    SET_SPI(TXFIFO, data);
    while ((GET_SPI(SPSR))&RFEMPTY); //wait for echo
    val = GET_SPI(RXFIFO);
    return val;
78 79
}

0
0xcccccccccccc 已提交
80
static int cmd_spi_init(int argc, char *argv[])
81
{
0
0xcccccccccccc 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
    uint8_t spre_spr, cpol, cpha;
    switch (argc)
    {
    case 2:
        spre_spr = strtoul(argv[1], NULL, 0);
        spi_init(spre_spr, 0, 0);
        break;
    case 4:
        spre_spr = strtoul(argv[1], NULL, 0);
        cpol = strtoul(argv[2], NULL, 0);
        cpha = strtoul(argv[3], NULL, 0);
        spi_init(spre_spr, 0, 0);
        break;
    default:
        printf("\nusage : cmd_spi_init spre_spr <cpol> <cpha>\n(cmd_spi_init 0x4 0x0 0x0)\n0x4:div8 0xb:div4096\n");
        break;
    }
99
}
0
0xcccccccccccc 已提交
100
MSH_CMD_EXPORT(cmd_spi_init, cmd_spi_init);
101

0
0xcccccccccccc 已提交
102
static int cmd_spi_set_csn(int argc, char *argv[])
103
{
0
0xcccccccccccc 已提交
104 105 106 107 108 109 110 111 112 113 114 115
    uint8_t val, csn;
    switch (argc)
    {
    case 3:
        csn = strtoul(argv[1], NULL, 0);
        val = strtoul(argv[2], NULL, 0);
        spi_set_cs(csn, val);
        break;
    default:
        printf("usage:cmd_spi_set_csn csn val\n(0xbf for csn1 enable,0xff for csn1 disable)\n");
        break;
    }
116
}
0
0xcccccccccccc 已提交
117
MSH_CMD_EXPORT(cmd_spi_set_csn, cmd_spi_set_csn);
118

0
0xcccccccccccc 已提交
119
static int cmd_spi_write(int argc, char *argv[])
120
{
0
0xcccccccccccc 已提交
121 122 123 124 125 126 127 128 129 130 131 132
    uint8_t data, resp;
    switch (argc)
    {
    case 2:
        data = strtoul(argv[1], NULL, 0);
        resp = spi_write_for_response(data);
        printf("resp:%2X\n", resp);
        break;
    default:
        printf("usage:cmd_spi_write data\n");
        break;
    }
133
}
0
0xcccccccccccc 已提交
134
MSH_CMD_EXPORT(cmd_spi_write, cmd_spi_write);
135 136 137

static rt_err_t configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
static rt_uint32_t xfer(struct rt_spi_device *device, struct rt_spi_message *message);
138

0
0xcccccccccccc 已提交
139 140
const static unsigned char SPI_DIV_TABLE[] = {0b0000, 0b0001, 0b0100, 0b0010, 0b0011, 0b0101, 0b0110, 0b0111, 0b1000, 0b1001, 0b1010, 0b1011};
// 2      4      8      16     32     64      128   256    512    1024   2048   4096
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
static rt_err_t configure(struct rt_spi_device *device,
                          struct rt_spi_configuration *configuration)
{

    unsigned char cpol = 0;
    unsigned char cpha = 0;

    RT_ASSERT(NULL != device);
    RT_ASSERT(NULL != configuration);

    // baudrate
    if (configuration->mode & RT_SPI_CPOL)      // cpol
    {
        cpol = 1;
    }
    else
    {
        cpol = 0;
    }
    if (configuration->mode & RT_SPI_CPHA)      // cpha
    {
        cpha = 1;
    }
    else
    {
        cpha = 0;
    }
0
0xcccccccccccc 已提交
168 169 170 171 172 173

    float spi_max_speed = ((float)APB_MAX_SPEED) / (8.0 / (float)APB_FREQSCALE);
    uint64_t div = (uint64_t)(spi_max_speed / (float)configuration->max_hz);
    int ctr = 0;
    while (div != 1 && ctr < 12)
    {
174
        ctr++;
0
0xcccccccccccc 已提交
175
        div = div >> 1;
176
    }
0
0xcccccccccccc 已提交
177
    spi_init(SPI_DIV_TABLE[ctr], cpol, cpha);
178 179 180

    return RT_EOK;
}
181 182

static rt_uint32_t xfer(struct rt_spi_device *device, struct rt_spi_message *message)
183 184 185 186 187 188 189 190 191
{

    unsigned char cs = 0;
    rt_uint32_t size = 0;
    const rt_uint8_t *send_ptr = NULL;
    rt_uint8_t *recv_ptr = NULL;
    rt_uint8_t data = 0;
    RT_ASSERT(NULL != device);
    RT_ASSERT(NULL != message);
0
0xcccccccccccc 已提交
192
    cs = (unsigned char)(device->parent.user_data);
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
    size = message->length;
    if (message->cs_take)
    {
        spi_set_cs(cs, 0);
    }
    // send data
    send_ptr = message->send_buf;
    recv_ptr = message->recv_buf;
    while (size--)
    {
        data = 0xFF;
        if (NULL != send_ptr)
        {
            data = *send_ptr++;
        }
        if (NULL != recv_ptr)
        {
            *recv_ptr++ = spi_write_for_response(data);
        }
        else
        {
            spi_write_for_response(data);
        }
    }
    // release cs
    if (message->cs_release)
    {
        spi_set_cs(cs, 1);
    }
    return message->length;
}
224

225 226 227 228 229 230
static struct rt_spi_ops loongson_spi_ops =
{
    .configure  = configure,
    .xfer       = xfer
};
static struct rt_spi_bus loongson_spi;
231

232
static int loongson_spi_init()
0
0xcccccccccccc 已提交
233
{
234
    //rt_kprintf("spi_init\n");
0
0xcccccccccccc 已提交
235
    return rt_spi_bus_register(&loongson_spi, "spi", &loongson_spi_ops);
236 237 238
}
INIT_BOARD_EXPORT(loongson_spi_init);
#endif
0
0xcccccccccccc 已提交
239
/*@}*/