1.1 --- a/docs/wiki/Getting_Started Fri Jan 01 01:49:35 2021 +0100
1.2 +++ b/docs/wiki/Getting_Started Sun Jan 03 17:28:35 2021 +0100
1.3 @@ -56,13 +56,12 @@
1.4 }}}
1.5
1.6 (Here, `$LANDFALL` needs to expand to the location of this distribution
1.7 -whereas `$L4DIR` needs to expand to the location of the L4Re/Fiasco.OC
1.8 -software.)
1.9 +whereas `$L4DIR` needs to expand to the location of the L4Re software.)
1.10
1.11 For example:
1.12
1.13 {{{
1.14 -~/L4/Landfall/tools/install.sh ~/L4/src
1.15 +~/L4/Landfall/tools/install.sh ~/L4/src/l4
1.16 }}}
1.17
1.18 (The repository root of the L4Re/Fiasco.OC distribution typically has a
2.1 --- a/pkg/devices/lib/cpm/include/cpm-jz4730.h Fri Jan 01 01:49:35 2021 +0100
2.2 +++ b/pkg/devices/lib/cpm/include/cpm-jz4730.h Sun Jan 03 17:28:35 2021 +0100
2.3 @@ -1,5 +1,7 @@
2.4 /*
2.5 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
2.6 + * CPM (clock and power management) support for the JZ4730.
2.7 + *
2.8 + * Copyright (C) 2017, 2018, 2020 Paul Boddie <paul@boddie.org.uk>
2.9 *
2.10 * This program is free software; you can redistribute it and/or
2.11 * modify it under the terms of the GNU General Public License as
2.12 @@ -69,6 +71,9 @@
2.13 void set_lcd_pixel_divider(uint16_t division);
2.14 void set_lcd_frequencies(uint32_t pclk, uint8_t ratio);
2.15
2.16 + void start_i2c();
2.17 + void stop_i2c();
2.18 +
2.19 void start_lcd();
2.20 void stop_lcd();
2.21
2.22 @@ -97,6 +102,9 @@
2.23 int jz4730_cpm_have_clock(void *cpm);
2.24 void jz4730_cpm_start_clock(void *cpm);
2.25
2.26 +void jz4730_cpm_start_i2c(void *cpm);
2.27 +void jz4730_cpm_stop_i2c(void *cpm);
2.28 +
2.29 void jz4730_cpm_start_lcd(void *cpm);
2.30 void jz4730_cpm_stop_lcd(void *cpm);
2.31
3.1 --- a/pkg/devices/lib/cpm/src/jz4730.cc Fri Jan 01 01:49:35 2021 +0100
3.2 +++ b/pkg/devices/lib/cpm/src/jz4730.cc Sun Jan 03 17:28:35 2021 +0100
3.3 @@ -3,7 +3,7 @@
3.4 * provided by the jz4730. The power management functionality could be exposed
3.5 * using a separate driver.
3.6 *
3.7 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
3.8 + * Copyright (C) 2017, 2018, 2020 Paul Boddie <paul@boddie.org.uk>
3.9 *
3.10 * This program is free software; you can redistribute it and/or
3.11 * modify it under the terms of the GNU General Public License as
3.12 @@ -57,8 +57,27 @@
3.13
3.14 enum Clock_gate_bits : unsigned
3.15 {
3.16 - Clock_gate_lcd = 7, // LCD
3.17 - Clock_gate_timer = 3, // OST
3.18 + Clock_gate_uprt = 25,
3.19 + Clock_gate_udc = 24,
3.20 + Clock_gate_cim = 23,
3.21 + Clock_gate_kbc = 22,
3.22 + Clock_gate_emac = 21,
3.23 + Clock_gate_uart3 = 20,
3.24 + Clock_gate_aic_bitclk = 18,
3.25 + Clock_gate_scc = 14,
3.26 + Clock_gate_msc = 13,
3.27 + Clock_gate_ssi = 12,
3.28 + Clock_gate_pwm1 = 11,
3.29 + Clock_gate_pmw0 = 10,
3.30 + Clock_gate_aic_pclk = 9,
3.31 + Clock_gate_i2c = 8,
3.32 + Clock_gate_lcd = 7,
3.33 + Clock_gate_uhc = 6,
3.34 + Clock_gate_dmac = 5,
3.35 + Clock_gate_timer = 3,
3.36 + Clock_gate_uart2 = 2,
3.37 + Clock_gate_uart1 = 1,
3.38 + Clock_gate_uart0 = 0,
3.39 };
3.40
3.41 enum Lcd_divider_bits : unsigned
3.42 @@ -269,6 +288,22 @@
3.43
3.44
3.45
3.46 +// I2C clock control.
3.47 +
3.48 +void
3.49 +Cpm_jz4730_chip::start_i2c()
3.50 +{
3.51 + _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_i2c);
3.52 +}
3.53 +
3.54 +void
3.55 +Cpm_jz4730_chip::stop_i2c()
3.56 +{
3.57 + _regs[Clock_gate] = _regs[Clock_gate] | (1 << Clock_gate_i2c);
3.58 +}
3.59 +
3.60 +
3.61 +
3.62 // LCD clock control.
3.63
3.64 void
3.65 @@ -380,6 +415,18 @@
3.66 }
3.67
3.68 void
3.69 +jz4730_cpm_start_i2c(void *cpm)
3.70 +{
3.71 + static_cast<Cpm_jz4730_chip *>(cpm)->start_i2c();
3.72 +}
3.73 +
3.74 +void
3.75 +jz4730_cpm_stop_i2c(void *cpm)
3.76 +{
3.77 + static_cast<Cpm_jz4730_chip *>(cpm)->stop_i2c();
3.78 +}
3.79 +
3.80 +void
3.81 jz4730_cpm_start_lcd(void *cpm)
3.82 {
3.83 static_cast<Cpm_jz4730_chip *>(cpm)->start_lcd();
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/pkg/devices/lib/i2c/include/i2c-jz4730.h Sun Jan 03 17:28:35 2021 +0100
4.3 @@ -0,0 +1,111 @@
4.4 +/*
4.5 + * I2C support for the JZ4730.
4.6 + *
4.7 + * Copyright (C) 2017, 2018, 2019, 2020 Paul Boddie <paul@boddie.org.uk>
4.8 + *
4.9 + * This program is free software; you can redistribute it and/or
4.10 + * modify it under the terms of the GNU General Public License as
4.11 + * published by the Free Software Foundation; either version 2 of
4.12 + * the License, or (at your option) any later version.
4.13 + *
4.14 + * This program is distributed in the hope that it will be useful,
4.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.17 + * GNU General Public License for more details.
4.18 + *
4.19 + * You should have received a copy of the GNU General Public License
4.20 + * along with this program; if not, write to the Free Software
4.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
4.22 + * Boston, MA 02110-1301, USA
4.23 + */
4.24 +
4.25 +#pragma once
4.26 +
4.27 +#include <l4/sys/types.h>
4.28 +#include <stdint.h>
4.29 +
4.30 +
4.31 +
4.32 +#ifdef __cplusplus
4.33 +
4.34 +#include <l4/devices/cpm-jz4730.h>
4.35 +#include <l4/devices/hw_mmio_register_block.h>
4.36 +
4.37 +// I2C channel.
4.38 +
4.39 +class I2c_jz4730_channel
4.40 +{
4.41 +private:
4.42 + Hw::Register_block<32> _regs;
4.43 + Cpm_jz4730_chip *_cpm;
4.44 + uint32_t _frequency;
4.45 +
4.46 +public:
4.47 + I2c_jz4730_channel(l4_addr_t start, Cpm_jz4730_chip *cpm,
4.48 + uint32_t frequency);
4.49 +
4.50 + void disable();
4.51 + void enable();
4.52 +
4.53 + unsigned int read(uint8_t address, uint8_t buf[], unsigned int length);
4.54 + unsigned int write(uint8_t address, uint8_t buf[], unsigned int length);
4.55 +
4.56 +protected:
4.57 + void set_frequency();
4.58 +
4.59 + // Transaction control.
4.60 +
4.61 + void set_address(uint8_t address, bool read);
4.62 +
4.63 + void request_next();
4.64 + void send_next();
4.65 + void signal_last();
4.66 +
4.67 + void start();
4.68 + void stop();
4.69 +
4.70 + // Specific status conditions.
4.71 +
4.72 + bool data_valid();
4.73 + bool nack();
4.74 + bool transferred();
4.75 +};
4.76 +
4.77 +// I2C device control.
4.78 +
4.79 +class I2c_jz4730_chip
4.80 +{
4.81 +private:
4.82 + l4_addr_t _start, _end;
4.83 + Cpm_jz4730_chip *_cpm;
4.84 + uint32_t _frequency;
4.85 +
4.86 +public:
4.87 + I2c_jz4730_chip(l4_addr_t start, l4_addr_t end, Cpm_jz4730_chip *cpm,
4.88 + uint32_t frequency);
4.89 +
4.90 + I2c_jz4730_channel *get_channel(uint8_t channel);
4.91 +};
4.92 +
4.93 +#endif /* __cplusplus */
4.94 +
4.95 +
4.96 +
4.97 +/* C language interface. */
4.98 +
4.99 +EXTERN_C_BEGIN
4.100 +
4.101 +void *jz4730_i2c_init(l4_addr_t start, l4_addr_t end, void *cpm,
4.102 + uint32_t frequency);
4.103 +
4.104 +void *jz4730_i2c_get_channel(void *i2c, uint8_t channel);
4.105 +
4.106 +void jz4730_i2c_disable(void *i2c_channel);
4.107 +
4.108 +void jz4730_i2c_enable(void *i2c_channel);
4.109 +
4.110 +unsigned int jz4730_i2c_read(void *i2c_channel, uint8_t address, uint8_t buf[], unsigned int length);
4.111 +
4.112 +unsigned int jz4730_i2c_write(void *i2c_channel, uint8_t address, uint8_t buf[], unsigned int length);
4.113 +
4.114 +EXTERN_C_END
5.1 --- a/pkg/devices/lib/i2c/include/i2c-jz4780.h Fri Jan 01 01:49:35 2021 +0100
5.2 +++ b/pkg/devices/lib/i2c/include/i2c-jz4780.h Sun Jan 03 17:28:35 2021 +0100
5.3 @@ -1,4 +1,6 @@
5.4 /*
5.5 + * I2C support for the JZ4780.
5.6 + *
5.7 * Copyright (C) 2017, 2018, 2019 Paul Boddie <paul@boddie.org.uk>
5.8 *
5.9 * This program is free software; you can redistribute it and/or
6.1 --- a/pkg/devices/lib/i2c/src/Makefile Fri Jan 01 01:49:35 2021 +0100
6.2 +++ b/pkg/devices/lib/i2c/src/Makefile Sun Jan 03 17:28:35 2021 +0100
6.3 @@ -4,7 +4,7 @@
6.4 TARGET = libi2c.o.a libi2c.o.so
6.5 PC_FILENAME := libdrivers-i2c
6.6
6.7 -SRC_CC := jz4780.cc
6.8 +SRC_CC := jz4730.cc jz4780.cc
6.9
6.10 PRIVATE_INCDIR += $(PKGDIR)/lib/i2c/include
6.11
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/pkg/devices/lib/i2c/src/jz4730.cc Sun Jan 03 17:28:35 2021 +0100
7.3 @@ -0,0 +1,324 @@
7.4 +/*
7.5 + * I2C support for the JZ4730.
7.6 + *
7.7 + * Copyright (C) 2017, 2018, 2020 Paul Boddie <paul@boddie.org.uk>
7.8 + *
7.9 + * This program is free software; you can redistribute it and/or
7.10 + * modify it under the terms of the GNU General Public License as
7.11 + * published by the Free Software Foundation; either version 2 of
7.12 + * the License, or (at your option) any later version.
7.13 + *
7.14 + * This program is distributed in the hope that it will be useful,
7.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7.17 + * GNU General Public License for more details.
7.18 + *
7.19 + * You should have received a copy of the GNU General Public License
7.20 + * along with this program; if not, write to the Free Software
7.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
7.22 + * Boston, MA 02110-1301, USA
7.23 + */
7.24 +
7.25 +#include <l4/devices/i2c-jz4730.h>
7.26 +#include <l4/devices/hw_mmio_register_block.h>
7.27 +
7.28 +#include <l4/sys/icu.h>
7.29 +#include <l4/util/util.h>
7.30 +
7.31 +#include <cstdio>
7.32 +
7.33 +/*
7.34 +I2C pins are dedicated to I2C only and are not GPIO-controlled:
7.35 +
7.36 +I2C0: Y4/SMB0_SDA, V5/SMB0_SCK
7.37 +
7.38 +Note that there is effectively only one I2C channel.
7.39 +*/
7.40 +
7.41 +enum Regs
7.42 +{
7.43 + I2c_data = 0x000, // I2CDR
7.44 + I2c_control = 0x004, // I2CCR
7.45 + I2c_status = 0x008, // I2CSR
7.46 + I2c_clock = 0x00c, // I2CGR
7.47 +};
7.48 +
7.49 +enum I2c_control_bits : unsigned
7.50 +{
7.51 + I2c_control_enable_irq = 0x10, // IEN
7.52 + I2c_control_start = 0x08, // STA
7.53 + I2c_control_stop = 0x04, // STO
7.54 + I2c_control_nack = 0x02, // AC
7.55 + I2c_control_enable = 0x01, // I2CE
7.56 +};
7.57 +
7.58 +enum I2c_status_bits : unsigned
7.59 +{
7.60 + I2c_status_buffer_nempty = 0x10, // STX
7.61 + I2c_status_busy = 0x08, // BUSY
7.62 + I2c_status_transmit_end = 0x04, // TEND
7.63 + I2c_status_data_valid = 0x02, // DRF
7.64 + I2c_status_nack = 0x01, // ACKF
7.65 +};
7.66 +
7.67 +enum I2c_clock_values : unsigned
7.68 +{
7.69 + I2c_clock_max = 0xffff,
7.70 + I2c_clock_min = 0,
7.71 +};
7.72 +
7.73 +
7.74 +
7.75 +// Initialise a channel.
7.76 +
7.77 +I2c_jz4730_channel::I2c_jz4730_channel(l4_addr_t start,
7.78 + Cpm_jz4730_chip *cpm,
7.79 + uint32_t frequency)
7.80 +: _cpm(cpm), _frequency(frequency)
7.81 +{
7.82 + _regs = new Hw::Mmio_register_block<32>(start);
7.83 +}
7.84 +
7.85 +// Enable the channel.
7.86 +
7.87 +void
7.88 +I2c_jz4730_channel::enable()
7.89 +{
7.90 + // Make sure that the I2C clock is available.
7.91 +
7.92 + _cpm->start_i2c();
7.93 +
7.94 + // Set the bus clock frequency.
7.95 +
7.96 + set_frequency();
7.97 +
7.98 + // Enable the channel and interrupts.
7.99 +
7.100 + _regs[I2c_control] = I2c_control_enable | I2c_control_enable_irq;
7.101 + while (!(_regs[I2c_control] & I2c_control_enable));
7.102 +}
7.103 +
7.104 +// Disable the channel.
7.105 +
7.106 +void
7.107 +I2c_jz4730_channel::disable()
7.108 +{
7.109 + _regs[I2c_control] = 0;
7.110 + while (_regs[I2c_control] & I2c_control_enable);
7.111 +}
7.112 +
7.113 +// Set the frequency-related peripheral parameters.
7.114 +
7.115 +void
7.116 +I2c_jz4730_channel::set_frequency()
7.117 +{
7.118 + // The APB clock (PCLK) is used to drive I2C transfers. Its value must be
7.119 + // obtained from the CPM unit and is scaled to kHz in order to keep the
7.120 + // numbers easily representable, as is the bus frequency.
7.121 +
7.122 + uint32_t pclk = _cpm->get_pclock_frequency() / 1000;
7.123 + uint32_t i2c_clk = _frequency / 1000;
7.124 + uint32_t division = pclk / (16 * i2c_clk);
7.125 +
7.126 + if (division > I2c_clock_min)
7.127 + {
7.128 + division -= 1;
7.129 + if (division > I2c_clock_max)
7.130 + division = I2c_clock_max;
7.131 + }
7.132 +
7.133 + _regs[I2c_clock] = division;
7.134 +}
7.135 +
7.136 +// Present the address on the bus.
7.137 +
7.138 +void
7.139 +I2c_jz4730_channel::set_address(uint8_t address, bool read)
7.140 +{
7.141 + start();
7.142 +
7.143 + while (nack());
7.144 +
7.145 + _regs[I2c_data] = (address << 1) | (read ? 1 : 0);
7.146 + send_next();
7.147 +
7.148 + if (read)
7.149 + while ((data_valid() || !transferred()) && !nack());
7.150 + else
7.151 + while (data_valid() && !nack());
7.152 +}
7.153 +
7.154 +// Read data from the bus.
7.155 +
7.156 +unsigned int
7.157 +I2c_jz4730_channel::read(uint8_t address, uint8_t buf[], unsigned int length)
7.158 +{
7.159 + unsigned int nread = 0;
7.160 +
7.161 + set_address(address, true);
7.162 +
7.163 + if (!nack())
7.164 + {
7.165 + if (length == 1)
7.166 + signal_last();
7.167 +
7.168 + while (nread < length)
7.169 + {
7.170 + while (!data_valid());
7.171 +
7.172 + if (nread == length - 2)
7.173 + signal_last();
7.174 +
7.175 + buf[nread++] = _regs[I2c_data];
7.176 + request_next();
7.177 + }
7.178 + }
7.179 +
7.180 + stop();
7.181 +
7.182 + return nread;
7.183 +}
7.184 +
7.185 +// Write data to the bus.
7.186 +
7.187 +unsigned int
7.188 +I2c_jz4730_channel::write(uint8_t address, uint8_t buf[], unsigned int length)
7.189 +{
7.190 + unsigned int nwritten = 0;
7.191 +
7.192 + set_address(address, false);
7.193 +
7.194 + while ((nwritten < length) && !nack())
7.195 + {
7.196 + _regs[I2c_data] = buf[nwritten++];
7.197 + send_next();
7.198 +
7.199 + while (data_valid() && !nack());
7.200 + }
7.201 +
7.202 + stop();
7.203 +
7.204 + while (!transferred());
7.205 +
7.206 + return nwritten;
7.207 +}
7.208 +
7.209 +// Test for data validity.
7.210 +
7.211 +bool
7.212 +I2c_jz4730_channel::data_valid()
7.213 +{
7.214 + return (_regs[I2c_status] & I2c_status_data_valid) ? true : false;
7.215 +}
7.216 +
7.217 +// Request the next byte by clearing the data validity flag.
7.218 +
7.219 +void
7.220 +I2c_jz4730_channel::request_next()
7.221 +{
7.222 + _regs[I2c_status] = _regs[I2c_status] & ~I2c_status_data_valid;
7.223 +}
7.224 +
7.225 +// Indicate data ready for sending.
7.226 +
7.227 +void
7.228 +I2c_jz4730_channel::send_next()
7.229 +{
7.230 + _regs[I2c_status] = _regs[I2c_status] | I2c_status_data_valid;
7.231 +}
7.232 +
7.233 +// Test for non-acknowledgement.
7.234 +
7.235 +bool
7.236 +I2c_jz4730_channel::nack()
7.237 +{
7.238 + return (_regs[I2c_status] & I2c_status_nack) ? true : false;
7.239 +}
7.240 +
7.241 +// Set non-acknowledgement when receiving data.
7.242 +
7.243 +void
7.244 +I2c_jz4730_channel::signal_last()
7.245 +{
7.246 + _regs[I2c_control] = _regs[I2c_control] | I2c_control_nack;
7.247 +}
7.248 +
7.249 +// Test for write transfer completion.
7.250 +
7.251 +bool
7.252 +I2c_jz4730_channel::transferred()
7.253 +{
7.254 + return (_regs[I2c_status] & I2c_status_transmit_end) ? true : false;
7.255 +}
7.256 +
7.257 +// Explicitly start communication.
7.258 +
7.259 +void
7.260 +I2c_jz4730_channel::start()
7.261 +{
7.262 + _regs[I2c_control] = (_regs[I2c_control] & ~I2c_control_nack) | I2c_control_start;
7.263 +}
7.264 +
7.265 +// Explicitly stop communication.
7.266 +
7.267 +void
7.268 +I2c_jz4730_channel::stop()
7.269 +{
7.270 + _regs[I2c_control] = _regs[I2c_control] | I2c_control_stop;
7.271 +}
7.272 +
7.273 +
7.274 +
7.275 +// Initialise the I2C controller.
7.276 +
7.277 +I2c_jz4730_chip::I2c_jz4730_chip(l4_addr_t start, l4_addr_t end,
7.278 + Cpm_jz4730_chip *cpm,
7.279 + uint32_t frequency)
7.280 +: _start(start), _end(end), _cpm(cpm), _frequency(frequency)
7.281 +{
7.282 +}
7.283 +
7.284 +// Obtain a channel object. Only one channel is supported.
7.285 +
7.286 +I2c_jz4730_channel *
7.287 +I2c_jz4730_chip::get_channel(uint8_t channel)
7.288 +{
7.289 + if (channel == 0)
7.290 + return new I2c_jz4730_channel(_start, _cpm, _frequency);
7.291 + else
7.292 + throw -L4_EINVAL;
7.293 +}
7.294 +
7.295 +
7.296 +
7.297 +// C language interface functions.
7.298 +
7.299 +void *jz4730_i2c_init(l4_addr_t start, l4_addr_t end, void *cpm, uint32_t frequency)
7.300 +{
7.301 + return (void *) new I2c_jz4730_chip(start, end, static_cast<Cpm_jz4730_chip *>(cpm), frequency);
7.302 +}
7.303 +
7.304 +void *jz4730_i2c_get_channel(void *i2c, uint8_t channel)
7.305 +{
7.306 + return static_cast<I2c_jz4730_chip *>(i2c)->get_channel(channel);
7.307 +}
7.308 +
7.309 +void jz4730_i2c_disable(void *i2c_channel)
7.310 +{
7.311 + static_cast<I2c_jz4730_channel *>(i2c_channel)->disable();
7.312 +}
7.313 +
7.314 +void jz4730_i2c_enable(void *i2c_channel)
7.315 +{
7.316 + static_cast<I2c_jz4730_channel *>(i2c_channel)->enable();
7.317 +}
7.318 +
7.319 +unsigned int jz4730_i2c_read(void *i2c_channel, uint8_t address, uint8_t buf[], unsigned int length)
7.320 +{
7.321 + return static_cast<I2c_jz4730_channel *>(i2c_channel)->read(address, buf, length);
7.322 +}
7.323 +
7.324 +unsigned int jz4730_i2c_write(void *i2c_channel, uint8_t address, uint8_t buf[], unsigned int length)
7.325 +{
7.326 + return static_cast<I2c_jz4730_channel *>(i2c_channel)->write(address, buf, length);
7.327 +}
8.1 --- a/pkg/devices/lib/i2c/src/jz4780.cc Fri Jan 01 01:49:35 2021 +0100
8.2 +++ b/pkg/devices/lib/i2c/src/jz4780.cc Sun Jan 03 17:28:35 2021 +0100
8.3 @@ -1,4 +1,6 @@
8.4 /*
8.5 + * I2C support for the JZ4780.
8.6 + *
8.7 * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
8.8 *
8.9 * This program is free software; you can redistribute it and/or
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/pkg/landfall-examples/letux400_i2c/Makefile Sun Jan 03 17:28:35 2021 +0100
9.3 @@ -0,0 +1,10 @@
9.4 +PKGDIR ?= ..
9.5 +L4DIR ?= $(PKGDIR)/../..
9.6 +
9.7 +TARGET = ex_letux400_i2c
9.8 +
9.9 +SRC_CC = letux400_i2c.cc
9.10 +
9.11 +REQUIRES_LIBS = l4re_c-util libdrivers-cpm libdrivers-i2c libdevice-util
9.12 +
9.13 +include $(L4DIR)/mk/prog.mk
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/pkg/landfall-examples/letux400_i2c/letux400_i2c.cc Sun Jan 03 17:28:35 2021 +0100
10.3 @@ -0,0 +1,157 @@
10.4 +/*
10.5 + * Access peripherals on the I2C bus.
10.6 + *
10.7 + * Copyright (C) 2018, 2020 Paul Boddie <paul@boddie.org.uk>
10.8 + *
10.9 + * This program is free software; you can redistribute it and/or
10.10 + * modify it under the terms of the GNU General Public License as
10.11 + * published by the Free Software Foundation; either version 2 of
10.12 + * the License, or (at your option) any later version.
10.13 + *
10.14 + * This program is distributed in the hope that it will be useful,
10.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
10.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10.17 + * GNU General Public License for more details.
10.18 + *
10.19 + * You should have received a copy of the GNU General Public License
10.20 + * along with this program; if not, write to the Free Software
10.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
10.22 + * Boston, MA 02110-1301, USA
10.23 + */
10.24 +
10.25 +#include <l4/devices/cpm-jz4730.h>
10.26 +#include <l4/devices/i2c-jz4730.h>
10.27 +#include <l4/devices/memory.h>
10.28 +
10.29 +#include <stdio.h>
10.30 +
10.31 +
10.32 +
10.33 +/* Scan the I2C bus by performing speculative reads from each device address. */
10.34 +
10.35 +static void i2c_scan(void *i2c_channel)
10.36 +{
10.37 + uint8_t buf[1];
10.38 + unsigned int address;
10.39 +
10.40 + for (address = 0; address < 0x20; address++)
10.41 + printf("%02x ", address);
10.42 + printf("\n");
10.43 +
10.44 + for (address = 0; address < 0x20; address++)
10.45 + printf("-- ");
10.46 +
10.47 + for (address = 0; address < 0x80; address++)
10.48 + {
10.49 + if ((address % 32) == 0)
10.50 + printf("\n");
10.51 +
10.52 + if (jz4730_i2c_read(i2c_channel, address, buf, 1))
10.53 + printf("%02x ", address);
10.54 + else
10.55 + printf("?? ");
10.56 + }
10.57 +
10.58 + printf("\n");
10.59 + for (address = 0; address < 0x20; address++)
10.60 + printf("-- ");
10.61 + printf("\n\n");
10.62 +}
10.63 +
10.64 +/* Interpret RTC registers. */
10.65 +
10.66 +static void rtc_datetime(uint8_t *rtcregs)
10.67 +{
10.68 + const char *weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
10.69 +
10.70 + printf("%s %d%d-%d%d-%d%d %d%d:%d%d:%d%d\n",
10.71 + weekdays[rtcregs[0x06] & 0x07],
10.72 + (rtcregs[0x08] & 0xf0) >> 4,
10.73 + rtcregs[0x08] & 0x0f,
10.74 + (rtcregs[0x07] & 0x10) >> 4,
10.75 + rtcregs[0x07] & 0x0f,
10.76 + (rtcregs[0x05] & 0x30) >> 4,
10.77 + rtcregs[0x05] & 0x0f,
10.78 + (rtcregs[0x04] & 0x30) >> 4,
10.79 + rtcregs[0x04] & 0x0f,
10.80 + (rtcregs[0x03] & 0x70) >> 4,
10.81 + rtcregs[0x03] & 0x0f,
10.82 + (rtcregs[0x02] & 0x70) >> 4,
10.83 + rtcregs[0x02] & 0x0f);
10.84 +}
10.85 +
10.86 +
10.87 +
10.88 +int main(void)
10.89 +{
10.90 + void *cpm;
10.91 + void *i2c, *i2c0;
10.92 +
10.93 + /* Peripheral memory. */
10.94 +
10.95 + l4_addr_t cpm_base = 0, cpm_base_end = 0;
10.96 + l4_addr_t i2c_base = 0, i2c_base_end = 0;
10.97 +
10.98 + /* Obtain resource details describing I/O memory. */
10.99 +
10.100 + printf("Access CPM...\n");
10.101 +
10.102 + if (get_memory("jz4730-cpm", &cpm_base, &cpm_base_end) < 0)
10.103 + return 1;
10.104 +
10.105 + printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end);
10.106 +
10.107 + printf("Access I2C...\n");
10.108 +
10.109 + if (get_memory("jz4730-i2c", &i2c_base, &i2c_base_end) < 0)
10.110 + return 1;
10.111 +
10.112 + printf("I2C at 0x%lx...0x%lx.\n", i2c_base, i2c_base_end);
10.113 +
10.114 + /* Obtain CPM and I2C references. */
10.115 +
10.116 + cpm = jz4730_cpm_init(cpm_base);
10.117 + i2c = jz4730_i2c_init(i2c_base, i2c_base_end, cpm, 100000); /* 100 kHz */
10.118 + i2c0 = jz4730_i2c_get_channel(i2c, 0);
10.119 +
10.120 + /* Enable I2C. */
10.121 +
10.122 + jz4730_i2c_enable(i2c0);
10.123 +
10.124 + uint8_t buf[32];
10.125 + unsigned int nwritten;
10.126 +
10.127 + /* Set the clock: 12:34:56 on Saturday 2nd January 2021. */
10.128 +
10.129 + buf[0] = 2; buf[1] = 0x56; buf[2] = 0x34; buf[3] = 0x12; buf[4] = 0x02; buf[5] = 0x06; buf[6] = 0x01; buf[7] = 0x21;
10.130 + nwritten = jz4730_i2c_write(i2c0, 0x51, buf, 8);
10.131 +
10.132 + printf("Written: %d\n", nwritten);
10.133 +
10.134 + /* Issue selection of device register 0. */
10.135 +
10.136 + buf[0] = 0;
10.137 + nwritten = jz4730_i2c_write(i2c0, 0x51, buf, 1);
10.138 +
10.139 + printf("Written: %d\n", nwritten);
10.140 +
10.141 + /* Read the contents of 16 registers. */
10.142 +
10.143 + unsigned int nread = jz4730_i2c_read(i2c0, 0x51, buf, 16);
10.144 +
10.145 + printf("Read: %d\n", nread);
10.146 + for (unsigned int i = 0; i < nread; i++)
10.147 + printf("%02x ", buf[i]);
10.148 + printf("\n");
10.149 +
10.150 + /* Show the interpreted date and time. */
10.151 +
10.152 + rtc_datetime(buf);
10.153 +
10.154 + /* Scan the bus. */
10.155 +
10.156 + printf("Scan I2C0...\n");
10.157 + i2c_scan(i2c0);
10.158 +
10.159 + return 0;
10.160 +}