123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575 |
- /*
- * Copyright (c) 2006-2019, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2019-07-29 zdzn first version
- */
- #include "bcm283x.h"
- rt_uint32_t bcm283x_peri_read(volatile rt_ubase_t addr)
- {
- rt_uint32_t ret;
- __sync_synchronize();
- ret = HWREG32(addr);
- __sync_synchronize();
- return ret;
- }
- rt_uint32_t bcm283x_peri_read_nb(volatile rt_ubase_t addr)
- {
- return HWREG32(addr);
- }
- void bcm283x_peri_write(volatile rt_ubase_t addr, rt_uint32_t value)
- {
- __sync_synchronize();
- HWREG32(addr) = value;
- __sync_synchronize();
- }
- void bcm283x_peri_write_nb(volatile rt_ubase_t addr, rt_uint32_t value)
- {
- HWREG32(addr) = value;
- }
- void bcm283x_peri_set_bits(volatile rt_ubase_t addr, rt_uint32_t value, rt_uint32_t mask)
- {
- rt_uint32_t v = bcm283x_peri_read(addr);
- v = (v & ~mask) | (value & mask);
- bcm283x_peri_write(addr, v);
- }
- void bcm283x_gpio_fsel(rt_uint8_t pin, rt_uint8_t mode)
- {
- volatile rt_ubase_t addr = (BCM283X_GPIO_BASE + BCM283X_GPIO_GPFSEL0 + (pin / 10) * 4);
- rt_uint8_t shift = (pin % 10) * 3;
- rt_uint32_t mask = BCM283X_GPIO_FSEL_MASK << shift;
- rt_uint32_t value = mode << shift;
- bcm283x_peri_set_bits(addr, value, mask);
- }
- void bcm283x_gpio_set(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPSET0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- bcm283x_peri_write(addr, 1 << shift);
- }
- void bcm283x_gpio_clr(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPCLR0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- bcm283x_peri_write(addr, 1 << shift);
- }
- rt_uint8_t bcm283x_gpio_lev(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM2835_GPIO_GPLEV0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = bcm283x_peri_read(addr);
- return (value & (1 << shift)) ? HIGH : LOW;
- }
- rt_uint8_t bcm283x_gpio_eds(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPEDS0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = bcm283x_peri_read(addr);
- return (value & (1 << shift)) ? HIGH : LOW;
- }
- /* Write a 1 to clear the bit in EDS */
- void bcm283x_gpio_set_eds(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPEDS0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_write(addr, value);
- }
- /* Rising edge detect enable */
- void bcm283x_gpio_ren(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPREN0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_set_bits(addr, value, value);
- }
- void bcm283x_gpio_clr_ren(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPREN0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_set_bits(addr, 0, value);
- }
- /* Falling edge detect enable */
- void bcm283x_gpio_fen(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPFEN0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_set_bits(addr, value, value);
- }
- void bcm283x_gpio_clr_fen(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPFEN0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_set_bits(addr, 0, value);
- }
- /* High detect enable */
- void bcm283x_gpio_hen(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPHEN0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_set_bits(addr, value, value);
- }
- void bcm283x_gpio_clr_hen(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPHEN0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_set_bits(addr, 0, value);
- }
- /* Low detect enable */
- void bcm283x_gpio_len(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPLEN0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_set_bits(addr, value, value);
- }
- void bcm283x_gpio_clr_len(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPLEN0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_set_bits(addr, 0, value);
- }
- /* Async rising edge detect enable */
- void bcm283x_gpio_aren(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPAREN0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_set_bits(addr, value, value);
- }
- void bcm283x_gpio_clr_aren(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPAREN0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_set_bits(addr, 0, value);
- }
- /* Async falling edge detect enable */
- void bcm283x_gpio_afen(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPAFEN0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_set_bits(addr, value, value);
- }
- void bcm283x_gpio_clr_afen(rt_uint8_t pin)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPAFEN0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- rt_uint32_t value = 1 << shift;
- bcm283x_peri_set_bits(addr, 0, value);
- }
- /* Set pullup/down */
- void bcm283x_gpio_pud(rt_uint8_t pud)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPPUD;
- bcm283x_peri_write(addr, pud);
- }
- /* Pullup/down clock
- // Clocks the value of pud into the GPIO pin
- */
- void bcm283x_gpio_pudclk(rt_uint8_t pin, rt_uint8_t on)
- {
- volatile rt_ubase_t addr = BCM283X_GPIO_BASE + BCM283X_GPIO_GPPUDCLK0 + (pin / 32) * 4;
- rt_uint8_t shift = pin % 32;
- bcm283x_peri_write(addr, (on? 1 : 0) << shift);
- }
- void bcm283x_gpio_set_pud(rt_uint8_t pin, rt_uint8_t pud)
- {
- bcm283x_gpio_pud(pud);
- bcm283x_clo_delayMicros(10);
- bcm283x_gpio_pudclk(pin, 1);
- bcm283x_clo_delayMicros(10);
- bcm283x_gpio_pud(BCM283X_GPIO_PUD_OFF);
- bcm283x_gpio_pudclk(pin, 0);
- }
- void bcm283x_gpio_write(rt_uint8_t pin, rt_uint8_t val)
- {
- if (val)
- bcm283x_gpio_set(pin);
- else
- bcm283x_gpio_clr(pin);
- }
- rt_uint64_t bcm283x_st_read(void)
- {
- volatile rt_ubase_t addr;
- rt_uint32_t hi, lo;
- rt_uint64_t st;
- addr = BCM283X_ST_BASE + BCM283X_ST_CHI;
- hi = bcm283x_peri_read(addr);
- addr = BCM283X_ST_BASE + BCM283X_ST_CLO;
- lo = bcm283x_peri_read(addr);
- addr = BCM283X_ST_BASE + BCM283X_ST_CHI;
- st = bcm283x_peri_read(addr);
- /* Test for overflow */
- if (st == hi)
- {
- rt_kprintf(">> 1crash???\n");
- st <<= 32;
- st += lo;
- rt_kprintf(">> 2crash!!!\n");
- }
- else
- {
- st <<= 32;
- addr = BCM283X_ST_BASE + BCM283X_ST_CLO;
- st += bcm283x_peri_read(addr);
- }
- return st;
- }
- /* microseconds */
- void bcm283x_delayMicroseconds(rt_uint64_t micros)
- {
- rt_uint64_t start;
- start = bcm283x_st_read();
- rt_kprintf("bcm283x_st_read result: %d\n", start);
- /* Not allowed to access timer registers (result is not as precise)*/
- if (start==0)
- return;
- bcm283x_st_delay(start, micros);
- }
- void bcm283x_clo_delayMicros(rt_uint32_t micros)
- {
- volatile rt_uint32_t addr;
- rt_uint32_t compare;
- addr = BCM283X_ST_BASE + BCM283X_ST_CLO;
- compare = bcm283x_peri_read(addr) + micros;
- while(bcm283x_peri_read(addr) < compare);
- }
- void bcm283x_st_delay(rt_uint64_t offset_micros, rt_uint64_t micros)
- {
- rt_uint64_t compare = offset_micros + micros;
- while(bcm283x_st_read() < compare);
- }
- /* Read an number of bytes from I2C */
- rt_uint8_t bcm283x_i2c_read(rt_uint32_t base, rt_uint8_t* buf, rt_uint32_t len)
- {
- volatile rt_uint32_t dlen = base + BCM283X_BSC_DLEN;
- volatile rt_uint32_t fifo = base + BCM283X_BSC_FIFO;
- volatile rt_uint32_t status = base + BCM283X_BSC_S;
- volatile rt_uint32_t control = base + BCM283X_BSC_C;
- rt_uint32_t remaining = len;
- rt_uint32_t i = 0;
- rt_uint8_t reason = BCM283X_I2C_REASON_OK;
- /* Clear FIFO */
- bcm283x_peri_set_bits(control, BCM283X_BSC_C_CLEAR_1, BCM283X_BSC_C_CLEAR_1);
- /* Clear Status */
- bcm283x_peri_write_nb(status, BCM283X_BSC_S_CLKT | BCM283X_BSC_S_ERR | BCM283X_BSC_S_DONE);
- /* Set Data Length */
- bcm283x_peri_write_nb(dlen, len);
- /* Start read */
- bcm283x_peri_write_nb(control, BCM283X_BSC_C_I2CEN | BCM283X_BSC_C_ST | BCM283X_BSC_C_READ);
- /* wait for transfer to complete */
- while (!(bcm283x_peri_read_nb(status) & BCM283X_BSC_S_DONE))
- {
- /* we must empty the FIFO as it is populated and not use any delay */
- while (remaining && bcm283x_peri_read_nb(status) & BCM283X_BSC_S_RXD)
- {
- /* Read from FIFO, no barrier */
- buf[i] = bcm283x_peri_read_nb(fifo);
- i++;
- remaining--;
- }
- }
- /* transfer has finished - grab any remaining stuff in FIFO */
- while (remaining && (bcm283x_peri_read_nb(status) & BCM283X_BSC_S_RXD))
- {
- /* Read from FIFO, no barrier */
- buf[i] = bcm283x_peri_read_nb(fifo);
- i++;
- remaining--;
- }
- /* Received a NACK */
- if (bcm283x_peri_read(status) & BCM283X_BSC_S_ERR)
- {
- reason = BCM283X_I2C_REASON_ERROR_NACK;
- }
- /* Received Clock Stretch Timeout */
- else if (bcm283x_peri_read(status) & BCM283X_BSC_S_CLKT)
- {
- reason = BCM283X_I2C_REASON_ERROR_CLKT;
- }
- /* Not all data is received */
- else if (remaining)
- {
- reason = BCM283X_I2C_REASON_ERROR_DATA;
- }
- bcm283x_peri_set_bits(control, BCM283X_BSC_S_DONE, BCM283X_BSC_S_DONE);
- return reason;
- }
- int bcm283x_i2c_begin(int no)
- {
- if (0 == no)
- {
- bcm283x_gpio_fsel(BCM_GPIO_PIN_0, BCM283X_GPIO_FSEL_ALT0); /* SDA */
- bcm283x_gpio_fsel(BCM_GPIO_PIN_1, BCM283X_GPIO_FSEL_ALT0); /* SCL */
- }
- else
- {
- bcm283x_gpio_fsel(BCM_GPIO_PIN_2, BCM283X_GPIO_FSEL_ALT0); /* SDA */
- bcm283x_gpio_fsel(BCM_GPIO_PIN_3, BCM283X_GPIO_FSEL_ALT0); /* SCL */
- }
- return 0;
- }
- void bcm283x_i2c_end(int no)
- {
- if (0 == no)
- {
- bcm283x_gpio_fsel(BCM_GPIO_PIN_0, BCM283X_GPIO_FSEL_INPT); /* SDA */
- bcm283x_gpio_fsel(BCM_GPIO_PIN_1, BCM283X_GPIO_FSEL_INPT); /* SCL */
- }
- else
- {
- bcm283x_gpio_fsel(BCM_GPIO_PIN_2, BCM283X_GPIO_FSEL_INPT); /* SDA */
- bcm283x_gpio_fsel(BCM_GPIO_PIN_3, BCM283X_GPIO_FSEL_INPT); /* SCL */
- }
- }
- void bcm283x_i2c_setSlaveAddress(int no, rt_uint8_t saddr)
- {
- volatile rt_uint32_t addr;
- if (0 == no)
- addr = PER_BASE + BCM283X_BSC0_BASE + BCM283X_BSC_A;
- else
- addr = PER_BASE + BCM283X_BSC1_BASE + BCM283X_BSC_A;
- bcm283x_peri_write(addr, saddr);
- }
- void bcm283x_i2c_setClockDivider(int no, rt_uint16_t divider)
- {
- volatile rt_uint32_t addr;
- if (0 == no)
- addr = PER_BASE + BCM283X_BSC0_BASE + BCM283X_BSC_DIV;
- else
- addr = PER_BASE + BCM283X_BSC0_BASE + BCM283X_BSC_DIV;
- bcm283x_peri_write(addr, divider);
- }
- void bcm283x_i2c_set_baudrate(int no, rt_uint32_t baudrate)
- {
- rt_uint32_t divider;
- divider = (BCM283X_CORE_CLK_HZ / baudrate) & 0xFFFE;
- bcm283x_i2c_setClockDivider(no, (rt_uint16_t)divider);
- }
- /* Writes an number of bytes to I2C */
- rt_uint8_t bcm283x_i2c_write(rt_uint32_t base, const rt_uint8_t * buf, rt_uint32_t len)
- {
- volatile rt_uint32_t dlen = base + BCM283X_BSC_DLEN;
- volatile rt_uint32_t fifo = base + BCM283X_BSC_FIFO;
- volatile rt_uint32_t status = base + BCM283X_BSC_S;
- volatile rt_uint32_t control = base + BCM283X_BSC_C;
- rt_uint32_t remaining = len;
- rt_uint32_t i = 0;
- rt_uint8_t reason = BCM283X_I2C_REASON_OK;
- /* Clear FIFO */
- bcm283x_peri_set_bits(control, BCM283X_BSC_C_CLEAR_1, BCM283X_BSC_C_CLEAR_1);
- /* Clear Status */
- bcm283x_peri_write(status, BCM283X_BSC_S_CLKT | BCM283X_BSC_S_ERR | BCM283X_BSC_S_DONE);
- /* Set Data Length */
- bcm283x_peri_write(dlen, len);
- /* pre populate FIFO with max buffer */
- while(remaining && (i < BCM283X_BSC_FIFO_SIZE))
- {
- bcm283x_peri_write_nb(fifo, buf[i]);
- i++;
- remaining--;
- }
- /* Enable device and start transfer */
- bcm283x_peri_write(control, BCM283X_BSC_C_I2CEN | BCM283X_BSC_C_ST);
- /* Transfer is over when BCM2835_BSC_S_DONE */
- while(!(bcm283x_peri_read(status) & BCM283X_BSC_S_DONE))
- {
- while (remaining && (bcm283x_peri_read(status) & BCM283X_BSC_S_TXD))
- {
- /* Write to FIFO */
- bcm283x_peri_write(fifo, buf[i]);
- i++;
- remaining--;
- }
- }
- /* Received a NACK */
- if (bcm283x_peri_read(status) & BCM283X_BSC_S_ERR)
- {
- reason = BCM283X_I2C_REASON_ERROR_NACK;
- }
- /* Received Clock Stretch Timeout */
- else if (bcm283x_peri_read(status) & BCM283X_BSC_S_CLKT)
- {
- reason = BCM283X_I2C_REASON_ERROR_CLKT;
- }
- /* Not all data is sent */
- else if (remaining)
- {
- reason = BCM283X_I2C_REASON_ERROR_DATA;
- }
- bcm283x_peri_set_bits(control, BCM283X_BSC_S_DONE, BCM283X_BSC_S_DONE);
- return reason;
- }
- rt_uint8_t bcm283x_i2c_write_read_rs(char* cmds, rt_uint32_t cmds_len, char* buf, rt_uint32_t buf_len)
- {
- volatile rt_uint32_t dlen = PER_BASE + BCM283X_BSC0_BASE + BCM283X_BSC_DLEN;
- volatile rt_uint32_t fifo = PER_BASE + BCM283X_BSC0_BASE + BCM283X_BSC_FIFO;
- volatile rt_uint32_t status = PER_BASE + BCM283X_BSC0_BASE + BCM283X_BSC_S;
- volatile rt_uint32_t control = PER_BASE + BCM283X_BSC0_BASE + BCM283X_BSC_C;
- rt_uint32_t remaining = cmds_len;
- rt_uint32_t i = 0;
- rt_uint8_t reason = BCM283X_I2C_REASON_OK;
- /* Clear FIFO */
- bcm283x_peri_set_bits(control, BCM283X_BSC_C_CLEAR_1, BCM283X_BSC_C_CLEAR_1);
- /* Clear Status */
- bcm283x_peri_write(status, BCM283X_BSC_S_CLKT | BCM283X_BSC_S_ERR | BCM283X_BSC_S_DONE);
- /* Set Data Length */
- bcm283x_peri_write(dlen, cmds_len);
- /* pre populate FIFO with max buffer */
- while(remaining && (i < BCM283X_BSC_FIFO_SIZE))
- {
- bcm283x_peri_write_nb(fifo, cmds[i]);
- i++;
- remaining--;
- }
- /* Enable device and start transfer */
- bcm283x_peri_write(control, BCM283X_BSC_C_I2CEN | BCM283X_BSC_C_ST);
- /* poll for transfer has started (way to do repeated start, from BCM2835 datasheet) */
- while (!(bcm283x_peri_read(status) & BCM283X_BSC_S_TA))
- {
- /* Linux may cause us to miss entire transfer stage */
- if (bcm283x_peri_read_nb(status) & BCM283X_BSC_S_DONE)
- break;
- }
- remaining = buf_len;
- i = 0;
- /* Send a repeated start with read bit set in address */
- bcm283x_peri_write(dlen, buf_len);
- bcm283x_peri_write(control, BCM283X_BSC_C_I2CEN | BCM283X_BSC_C_ST | BCM283X_BSC_C_READ);
- /* Wait for write to complete and first byte back. */
- bcm283x_clo_delayMicros(100);
- /* wait for transfer to complete */
- while (!(bcm283x_peri_read_nb(status) & BCM283X_BSC_S_DONE))
- {
- /* we must empty the FIFO as it is populated and not use any delay */
- while (remaining && bcm283x_peri_read(status) & BCM283X_BSC_S_RXD)
- {
- /* Read from FIFO, no barrier */
- buf[i] = bcm283x_peri_read_nb(fifo);
- i++;
- remaining--;
- }
- }
- /* transfer has finished - grab any remaining stuff in FIFO */
- while (remaining && (bcm283x_peri_read(status) & BCM283X_BSC_S_RXD))
- {
- /* Read from FIFO */
- buf[i] = bcm283x_peri_read(fifo);
- i++;
- remaining--;
- }
- /* Received a NACK */
- if (bcm283x_peri_read(status) & BCM283X_BSC_S_ERR)
- {
- reason = BCM283X_I2C_REASON_ERROR_NACK;
- }
- /* Received Clock Stretch Timeout */
- else if (bcm283x_peri_read(status) & BCM283X_BSC_S_CLKT)
- {
- reason = BCM283X_I2C_REASON_ERROR_CLKT;
- }
- /* Not all data is sent */
- else if (remaining)
- {
- reason = BCM283X_I2C_REASON_ERROR_DATA;
- }
- bcm283x_peri_set_bits(control, BCM283X_BSC_S_DONE, BCM283X_BSC_S_DONE);
- return reason;
- }
|