1.1 --- a/pkg/devices/lib/cpm/include/cpm-jz4730.h Thu Dec 31 18:09:12 2020 +0100 1.2 +++ b/pkg/devices/lib/cpm/include/cpm-jz4730.h Sun Jan 03 17:28:05 2021 +0100 1.3 @@ -1,5 +1,7 @@ 1.4 /* 1.5 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk> 1.6 + * CPM (clock and power management) support for the JZ4730. 1.7 + * 1.8 + * Copyright (C) 2017, 2018, 2020 Paul Boddie <paul@boddie.org.uk> 1.9 * 1.10 * This program is free software; you can redistribute it and/or 1.11 * modify it under the terms of the GNU General Public License as 1.12 @@ -69,6 +71,9 @@ 1.13 void set_lcd_pixel_divider(uint16_t division); 1.14 void set_lcd_frequencies(uint32_t pclk, uint8_t ratio); 1.15 1.16 + void start_i2c(); 1.17 + void stop_i2c(); 1.18 + 1.19 void start_lcd(); 1.20 void stop_lcd(); 1.21 1.22 @@ -97,6 +102,9 @@ 1.23 int jz4730_cpm_have_clock(void *cpm); 1.24 void jz4730_cpm_start_clock(void *cpm); 1.25 1.26 +void jz4730_cpm_start_i2c(void *cpm); 1.27 +void jz4730_cpm_stop_i2c(void *cpm); 1.28 + 1.29 void jz4730_cpm_start_lcd(void *cpm); 1.30 void jz4730_cpm_stop_lcd(void *cpm); 1.31
2.1 --- a/pkg/devices/lib/cpm/src/jz4730.cc Thu Dec 31 18:09:12 2020 +0100 2.2 +++ b/pkg/devices/lib/cpm/src/jz4730.cc Sun Jan 03 17:28:05 2021 +0100 2.3 @@ -3,7 +3,7 @@ 2.4 * provided by the jz4730. The power management functionality could be exposed 2.5 * using a separate driver. 2.6 * 2.7 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk> 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 @@ -57,8 +57,27 @@ 2.13 2.14 enum Clock_gate_bits : unsigned 2.15 { 2.16 - Clock_gate_lcd = 7, // LCD 2.17 - Clock_gate_timer = 3, // OST 2.18 + Clock_gate_uprt = 25, 2.19 + Clock_gate_udc = 24, 2.20 + Clock_gate_cim = 23, 2.21 + Clock_gate_kbc = 22, 2.22 + Clock_gate_emac = 21, 2.23 + Clock_gate_uart3 = 20, 2.24 + Clock_gate_aic_bitclk = 18, 2.25 + Clock_gate_scc = 14, 2.26 + Clock_gate_msc = 13, 2.27 + Clock_gate_ssi = 12, 2.28 + Clock_gate_pwm1 = 11, 2.29 + Clock_gate_pmw0 = 10, 2.30 + Clock_gate_aic_pclk = 9, 2.31 + Clock_gate_i2c = 8, 2.32 + Clock_gate_lcd = 7, 2.33 + Clock_gate_uhc = 6, 2.34 + Clock_gate_dmac = 5, 2.35 + Clock_gate_timer = 3, 2.36 + Clock_gate_uart2 = 2, 2.37 + Clock_gate_uart1 = 1, 2.38 + Clock_gate_uart0 = 0, 2.39 }; 2.40 2.41 enum Lcd_divider_bits : unsigned 2.42 @@ -269,6 +288,22 @@ 2.43 2.44 2.45 2.46 +// I2C clock control. 2.47 + 2.48 +void 2.49 +Cpm_jz4730_chip::start_i2c() 2.50 +{ 2.51 + _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_i2c); 2.52 +} 2.53 + 2.54 +void 2.55 +Cpm_jz4730_chip::stop_i2c() 2.56 +{ 2.57 + _regs[Clock_gate] = _regs[Clock_gate] | (1 << Clock_gate_i2c); 2.58 +} 2.59 + 2.60 + 2.61 + 2.62 // LCD clock control. 2.63 2.64 void 2.65 @@ -380,6 +415,18 @@ 2.66 } 2.67 2.68 void 2.69 +jz4730_cpm_start_i2c(void *cpm) 2.70 +{ 2.71 + static_cast<Cpm_jz4730_chip *>(cpm)->start_i2c(); 2.72 +} 2.73 + 2.74 +void 2.75 +jz4730_cpm_stop_i2c(void *cpm) 2.76 +{ 2.77 + static_cast<Cpm_jz4730_chip *>(cpm)->stop_i2c(); 2.78 +} 2.79 + 2.80 +void 2.81 jz4730_cpm_start_lcd(void *cpm) 2.82 { 2.83 static_cast<Cpm_jz4730_chip *>(cpm)->start_lcd();
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/pkg/devices/lib/i2c/include/i2c-jz4730.h Sun Jan 03 17:28:05 2021 +0100 3.3 @@ -0,0 +1,111 @@ 3.4 +/* 3.5 + * I2C support for the JZ4730. 3.6 + * 3.7 + * Copyright (C) 2017, 2018, 2019, 2020 Paul Boddie <paul@boddie.org.uk> 3.8 + * 3.9 + * This program is free software; you can redistribute it and/or 3.10 + * modify it under the terms of the GNU General Public License as 3.11 + * published by the Free Software Foundation; either version 2 of 3.12 + * the License, or (at your option) any later version. 3.13 + * 3.14 + * This program is distributed in the hope that it will be useful, 3.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 3.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 3.17 + * GNU General Public License for more details. 3.18 + * 3.19 + * You should have received a copy of the GNU General Public License 3.20 + * along with this program; if not, write to the Free Software 3.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 3.22 + * Boston, MA 02110-1301, USA 3.23 + */ 3.24 + 3.25 +#pragma once 3.26 + 3.27 +#include <l4/sys/types.h> 3.28 +#include <stdint.h> 3.29 + 3.30 + 3.31 + 3.32 +#ifdef __cplusplus 3.33 + 3.34 +#include <l4/devices/cpm-jz4730.h> 3.35 +#include <l4/devices/hw_mmio_register_block.h> 3.36 + 3.37 +// I2C channel. 3.38 + 3.39 +class I2c_jz4730_channel 3.40 +{ 3.41 +private: 3.42 + Hw::Register_block<32> _regs; 3.43 + Cpm_jz4730_chip *_cpm; 3.44 + uint32_t _frequency; 3.45 + 3.46 +public: 3.47 + I2c_jz4730_channel(l4_addr_t start, Cpm_jz4730_chip *cpm, 3.48 + uint32_t frequency); 3.49 + 3.50 + void disable(); 3.51 + void enable(); 3.52 + 3.53 + unsigned int read(uint8_t address, uint8_t buf[], unsigned int length); 3.54 + unsigned int write(uint8_t address, uint8_t buf[], unsigned int length); 3.55 + 3.56 +protected: 3.57 + void set_frequency(); 3.58 + 3.59 + // Transaction control. 3.60 + 3.61 + void set_address(uint8_t address, bool read); 3.62 + 3.63 + void request_next(); 3.64 + void send_next(); 3.65 + void signal_last(); 3.66 + 3.67 + void start(); 3.68 + void stop(); 3.69 + 3.70 + // Specific status conditions. 3.71 + 3.72 + bool data_valid(); 3.73 + bool nack(); 3.74 + bool transferred(); 3.75 +}; 3.76 + 3.77 +// I2C device control. 3.78 + 3.79 +class I2c_jz4730_chip 3.80 +{ 3.81 +private: 3.82 + l4_addr_t _start, _end; 3.83 + Cpm_jz4730_chip *_cpm; 3.84 + uint32_t _frequency; 3.85 + 3.86 +public: 3.87 + I2c_jz4730_chip(l4_addr_t start, l4_addr_t end, Cpm_jz4730_chip *cpm, 3.88 + uint32_t frequency); 3.89 + 3.90 + I2c_jz4730_channel *get_channel(uint8_t channel); 3.91 +}; 3.92 + 3.93 +#endif /* __cplusplus */ 3.94 + 3.95 + 3.96 + 3.97 +/* C language interface. */ 3.98 + 3.99 +EXTERN_C_BEGIN 3.100 + 3.101 +void *jz4730_i2c_init(l4_addr_t start, l4_addr_t end, void *cpm, 3.102 + uint32_t frequency); 3.103 + 3.104 +void *jz4730_i2c_get_channel(void *i2c, uint8_t channel); 3.105 + 3.106 +void jz4730_i2c_disable(void *i2c_channel); 3.107 + 3.108 +void jz4730_i2c_enable(void *i2c_channel); 3.109 + 3.110 +unsigned int jz4730_i2c_read(void *i2c_channel, uint8_t address, uint8_t buf[], unsigned int length); 3.111 + 3.112 +unsigned int jz4730_i2c_write(void *i2c_channel, uint8_t address, uint8_t buf[], unsigned int length); 3.113 + 3.114 +EXTERN_C_END
4.1 --- a/pkg/devices/lib/i2c/include/i2c-jz4780.h Thu Dec 31 18:09:12 2020 +0100 4.2 +++ b/pkg/devices/lib/i2c/include/i2c-jz4780.h Sun Jan 03 17:28:05 2021 +0100 4.3 @@ -1,4 +1,6 @@ 4.4 /* 4.5 + * I2C support for the JZ4780. 4.6 + * 4.7 * Copyright (C) 2017, 2018, 2019 Paul Boddie <paul@boddie.org.uk> 4.8 * 4.9 * This program is free software; you can redistribute it and/or
5.1 --- a/pkg/devices/lib/i2c/src/Makefile Thu Dec 31 18:09:12 2020 +0100 5.2 +++ b/pkg/devices/lib/i2c/src/Makefile Sun Jan 03 17:28:05 2021 +0100 5.3 @@ -4,7 +4,7 @@ 5.4 TARGET = libi2c.o.a libi2c.o.so 5.5 PC_FILENAME := libdrivers-i2c 5.6 5.7 -SRC_CC := jz4780.cc 5.8 +SRC_CC := jz4730.cc jz4780.cc 5.9 5.10 PRIVATE_INCDIR += $(PKGDIR)/lib/i2c/include 5.11
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/pkg/devices/lib/i2c/src/jz4730.cc Sun Jan 03 17:28:05 2021 +0100 6.3 @@ -0,0 +1,324 @@ 6.4 +/* 6.5 + * I2C support for the JZ4730. 6.6 + * 6.7 + * Copyright (C) 2017, 2018, 2020 Paul Boddie <paul@boddie.org.uk> 6.8 + * 6.9 + * This program is free software; you can redistribute it and/or 6.10 + * modify it under the terms of the GNU General Public License as 6.11 + * published by the Free Software Foundation; either version 2 of 6.12 + * the License, or (at your option) any later version. 6.13 + * 6.14 + * This program is distributed in the hope that it will be useful, 6.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 6.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 6.17 + * GNU General Public License for more details. 6.18 + * 6.19 + * You should have received a copy of the GNU General Public License 6.20 + * along with this program; if not, write to the Free Software 6.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 6.22 + * Boston, MA 02110-1301, USA 6.23 + */ 6.24 + 6.25 +#include <l4/devices/i2c-jz4730.h> 6.26 +#include <l4/devices/hw_mmio_register_block.h> 6.27 + 6.28 +#include <l4/sys/icu.h> 6.29 +#include <l4/util/util.h> 6.30 + 6.31 +#include <cstdio> 6.32 + 6.33 +/* 6.34 +I2C pins are dedicated to I2C only and are not GPIO-controlled: 6.35 + 6.36 +I2C0: Y4/SMB0_SDA, V5/SMB0_SCK 6.37 + 6.38 +Note that there is effectively only one I2C channel. 6.39 +*/ 6.40 + 6.41 +enum Regs 6.42 +{ 6.43 + I2c_data = 0x000, // I2CDR 6.44 + I2c_control = 0x004, // I2CCR 6.45 + I2c_status = 0x008, // I2CSR 6.46 + I2c_clock = 0x00c, // I2CGR 6.47 +}; 6.48 + 6.49 +enum I2c_control_bits : unsigned 6.50 +{ 6.51 + I2c_control_enable_irq = 0x10, // IEN 6.52 + I2c_control_start = 0x08, // STA 6.53 + I2c_control_stop = 0x04, // STO 6.54 + I2c_control_nack = 0x02, // AC 6.55 + I2c_control_enable = 0x01, // I2CE 6.56 +}; 6.57 + 6.58 +enum I2c_status_bits : unsigned 6.59 +{ 6.60 + I2c_status_buffer_nempty = 0x10, // STX 6.61 + I2c_status_busy = 0x08, // BUSY 6.62 + I2c_status_transmit_end = 0x04, // TEND 6.63 + I2c_status_data_valid = 0x02, // DRF 6.64 + I2c_status_nack = 0x01, // ACKF 6.65 +}; 6.66 + 6.67 +enum I2c_clock_values : unsigned 6.68 +{ 6.69 + I2c_clock_max = 0xffff, 6.70 + I2c_clock_min = 0, 6.71 +}; 6.72 + 6.73 + 6.74 + 6.75 +// Initialise a channel. 6.76 + 6.77 +I2c_jz4730_channel::I2c_jz4730_channel(l4_addr_t start, 6.78 + Cpm_jz4730_chip *cpm, 6.79 + uint32_t frequency) 6.80 +: _cpm(cpm), _frequency(frequency) 6.81 +{ 6.82 + _regs = new Hw::Mmio_register_block<32>(start); 6.83 +} 6.84 + 6.85 +// Enable the channel. 6.86 + 6.87 +void 6.88 +I2c_jz4730_channel::enable() 6.89 +{ 6.90 + // Make sure that the I2C clock is available. 6.91 + 6.92 + _cpm->start_i2c(); 6.93 + 6.94 + // Set the bus clock frequency. 6.95 + 6.96 + set_frequency(); 6.97 + 6.98 + // Enable the channel and interrupts. 6.99 + 6.100 + _regs[I2c_control] = I2c_control_enable | I2c_control_enable_irq; 6.101 + while (!(_regs[I2c_control] & I2c_control_enable)); 6.102 +} 6.103 + 6.104 +// Disable the channel. 6.105 + 6.106 +void 6.107 +I2c_jz4730_channel::disable() 6.108 +{ 6.109 + _regs[I2c_control] = 0; 6.110 + while (_regs[I2c_control] & I2c_control_enable); 6.111 +} 6.112 + 6.113 +// Set the frequency-related peripheral parameters. 6.114 + 6.115 +void 6.116 +I2c_jz4730_channel::set_frequency() 6.117 +{ 6.118 + // The APB clock (PCLK) is used to drive I2C transfers. Its value must be 6.119 + // obtained from the CPM unit and is scaled to kHz in order to keep the 6.120 + // numbers easily representable, as is the bus frequency. 6.121 + 6.122 + uint32_t pclk = _cpm->get_pclock_frequency() / 1000; 6.123 + uint32_t i2c_clk = _frequency / 1000; 6.124 + uint32_t division = pclk / (16 * i2c_clk); 6.125 + 6.126 + if (division > I2c_clock_min) 6.127 + { 6.128 + division -= 1; 6.129 + if (division > I2c_clock_max) 6.130 + division = I2c_clock_max; 6.131 + } 6.132 + 6.133 + _regs[I2c_clock] = division; 6.134 +} 6.135 + 6.136 +// Present the address on the bus. 6.137 + 6.138 +void 6.139 +I2c_jz4730_channel::set_address(uint8_t address, bool read) 6.140 +{ 6.141 + start(); 6.142 + 6.143 + while (nack()); 6.144 + 6.145 + _regs[I2c_data] = (address << 1) | (read ? 1 : 0); 6.146 + send_next(); 6.147 + 6.148 + if (read) 6.149 + while ((data_valid() || !transferred()) && !nack()); 6.150 + else 6.151 + while (data_valid() && !nack()); 6.152 +} 6.153 + 6.154 +// Read data from the bus. 6.155 + 6.156 +unsigned int 6.157 +I2c_jz4730_channel::read(uint8_t address, uint8_t buf[], unsigned int length) 6.158 +{ 6.159 + unsigned int nread = 0; 6.160 + 6.161 + set_address(address, true); 6.162 + 6.163 + if (!nack()) 6.164 + { 6.165 + if (length == 1) 6.166 + signal_last(); 6.167 + 6.168 + while (nread < length) 6.169 + { 6.170 + while (!data_valid()); 6.171 + 6.172 + if (nread == length - 2) 6.173 + signal_last(); 6.174 + 6.175 + buf[nread++] = _regs[I2c_data]; 6.176 + request_next(); 6.177 + } 6.178 + } 6.179 + 6.180 + stop(); 6.181 + 6.182 + return nread; 6.183 +} 6.184 + 6.185 +// Write data to the bus. 6.186 + 6.187 +unsigned int 6.188 +I2c_jz4730_channel::write(uint8_t address, uint8_t buf[], unsigned int length) 6.189 +{ 6.190 + unsigned int nwritten = 0; 6.191 + 6.192 + set_address(address, false); 6.193 + 6.194 + while ((nwritten < length) && !nack()) 6.195 + { 6.196 + _regs[I2c_data] = buf[nwritten++]; 6.197 + send_next(); 6.198 + 6.199 + while (data_valid() && !nack()); 6.200 + } 6.201 + 6.202 + stop(); 6.203 + 6.204 + while (!transferred()); 6.205 + 6.206 + return nwritten; 6.207 +} 6.208 + 6.209 +// Test for data validity. 6.210 + 6.211 +bool 6.212 +I2c_jz4730_channel::data_valid() 6.213 +{ 6.214 + return (_regs[I2c_status] & I2c_status_data_valid) ? true : false; 6.215 +} 6.216 + 6.217 +// Request the next byte by clearing the data validity flag. 6.218 + 6.219 +void 6.220 +I2c_jz4730_channel::request_next() 6.221 +{ 6.222 + _regs[I2c_status] = _regs[I2c_status] & ~I2c_status_data_valid; 6.223 +} 6.224 + 6.225 +// Indicate data ready for sending. 6.226 + 6.227 +void 6.228 +I2c_jz4730_channel::send_next() 6.229 +{ 6.230 + _regs[I2c_status] = _regs[I2c_status] | I2c_status_data_valid; 6.231 +} 6.232 + 6.233 +// Test for non-acknowledgement. 6.234 + 6.235 +bool 6.236 +I2c_jz4730_channel::nack() 6.237 +{ 6.238 + return (_regs[I2c_status] & I2c_status_nack) ? true : false; 6.239 +} 6.240 + 6.241 +// Set non-acknowledgement when receiving data. 6.242 + 6.243 +void 6.244 +I2c_jz4730_channel::signal_last() 6.245 +{ 6.246 + _regs[I2c_control] = _regs[I2c_control] | I2c_control_nack; 6.247 +} 6.248 + 6.249 +// Test for write transfer completion. 6.250 + 6.251 +bool 6.252 +I2c_jz4730_channel::transferred() 6.253 +{ 6.254 + return (_regs[I2c_status] & I2c_status_transmit_end) ? true : false; 6.255 +} 6.256 + 6.257 +// Explicitly start communication. 6.258 + 6.259 +void 6.260 +I2c_jz4730_channel::start() 6.261 +{ 6.262 + _regs[I2c_control] = (_regs[I2c_control] & ~I2c_control_nack) | I2c_control_start; 6.263 +} 6.264 + 6.265 +// Explicitly stop communication. 6.266 + 6.267 +void 6.268 +I2c_jz4730_channel::stop() 6.269 +{ 6.270 + _regs[I2c_control] = _regs[I2c_control] | I2c_control_stop; 6.271 +} 6.272 + 6.273 + 6.274 + 6.275 +// Initialise the I2C controller. 6.276 + 6.277 +I2c_jz4730_chip::I2c_jz4730_chip(l4_addr_t start, l4_addr_t end, 6.278 + Cpm_jz4730_chip *cpm, 6.279 + uint32_t frequency) 6.280 +: _start(start), _end(end), _cpm(cpm), _frequency(frequency) 6.281 +{ 6.282 +} 6.283 + 6.284 +// Obtain a channel object. Only one channel is supported. 6.285 + 6.286 +I2c_jz4730_channel * 6.287 +I2c_jz4730_chip::get_channel(uint8_t channel) 6.288 +{ 6.289 + if (channel == 0) 6.290 + return new I2c_jz4730_channel(_start, _cpm, _frequency); 6.291 + else 6.292 + throw -L4_EINVAL; 6.293 +} 6.294 + 6.295 + 6.296 + 6.297 +// C language interface functions. 6.298 + 6.299 +void *jz4730_i2c_init(l4_addr_t start, l4_addr_t end, void *cpm, uint32_t frequency) 6.300 +{ 6.301 + return (void *) new I2c_jz4730_chip(start, end, static_cast<Cpm_jz4730_chip *>(cpm), frequency); 6.302 +} 6.303 + 6.304 +void *jz4730_i2c_get_channel(void *i2c, uint8_t channel) 6.305 +{ 6.306 + return static_cast<I2c_jz4730_chip *>(i2c)->get_channel(channel); 6.307 +} 6.308 + 6.309 +void jz4730_i2c_disable(void *i2c_channel) 6.310 +{ 6.311 + static_cast<I2c_jz4730_channel *>(i2c_channel)->disable(); 6.312 +} 6.313 + 6.314 +void jz4730_i2c_enable(void *i2c_channel) 6.315 +{ 6.316 + static_cast<I2c_jz4730_channel *>(i2c_channel)->enable(); 6.317 +} 6.318 + 6.319 +unsigned int jz4730_i2c_read(void *i2c_channel, uint8_t address, uint8_t buf[], unsigned int length) 6.320 +{ 6.321 + return static_cast<I2c_jz4730_channel *>(i2c_channel)->read(address, buf, length); 6.322 +} 6.323 + 6.324 +unsigned int jz4730_i2c_write(void *i2c_channel, uint8_t address, uint8_t buf[], unsigned int length) 6.325 +{ 6.326 + return static_cast<I2c_jz4730_channel *>(i2c_channel)->write(address, buf, length); 6.327 +}
7.1 --- a/pkg/devices/lib/i2c/src/jz4780.cc Thu Dec 31 18:09:12 2020 +0100 7.2 +++ b/pkg/devices/lib/i2c/src/jz4780.cc Sun Jan 03 17:28:05 2021 +0100 7.3 @@ -1,4 +1,6 @@ 7.4 /* 7.5 + * I2C support for the JZ4780. 7.6 + * 7.7 * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk> 7.8 * 7.9 * This program is free software; you can redistribute it and/or
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/pkg/landfall-examples/letux400_i2c/Makefile Sun Jan 03 17:28:05 2021 +0100 8.3 @@ -0,0 +1,10 @@ 8.4 +PKGDIR ?= .. 8.5 +L4DIR ?= $(PKGDIR)/../.. 8.6 + 8.7 +TARGET = ex_letux400_i2c 8.8 + 8.9 +SRC_CC = letux400_i2c.cc 8.10 + 8.11 +REQUIRES_LIBS = l4re_c-util libdrivers-cpm libdrivers-i2c libdevice-util 8.12 + 8.13 +include $(L4DIR)/mk/prog.mk
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/pkg/landfall-examples/letux400_i2c/letux400_i2c.cc Sun Jan 03 17:28:05 2021 +0100 9.3 @@ -0,0 +1,157 @@ 9.4 +/* 9.5 + * Access peripherals on the I2C bus. 9.6 + * 9.7 + * Copyright (C) 2018, 2020 Paul Boddie <paul@boddie.org.uk> 9.8 + * 9.9 + * This program is free software; you can redistribute it and/or 9.10 + * modify it under the terms of the GNU General Public License as 9.11 + * published by the Free Software Foundation; either version 2 of 9.12 + * the License, or (at your option) any later version. 9.13 + * 9.14 + * This program is distributed in the hope that it will be useful, 9.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 9.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9.17 + * GNU General Public License for more details. 9.18 + * 9.19 + * You should have received a copy of the GNU General Public License 9.20 + * along with this program; if not, write to the Free Software 9.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 9.22 + * Boston, MA 02110-1301, USA 9.23 + */ 9.24 + 9.25 +#include <l4/devices/cpm-jz4730.h> 9.26 +#include <l4/devices/i2c-jz4730.h> 9.27 +#include <l4/devices/memory.h> 9.28 + 9.29 +#include <stdio.h> 9.30 + 9.31 + 9.32 + 9.33 +/* Scan the I2C bus by performing speculative reads from each device address. */ 9.34 + 9.35 +static void i2c_scan(void *i2c_channel) 9.36 +{ 9.37 + uint8_t buf[1]; 9.38 + unsigned int address; 9.39 + 9.40 + for (address = 0; address < 0x20; address++) 9.41 + printf("%02x ", address); 9.42 + printf("\n"); 9.43 + 9.44 + for (address = 0; address < 0x20; address++) 9.45 + printf("-- "); 9.46 + 9.47 + for (address = 0; address < 0x80; address++) 9.48 + { 9.49 + if ((address % 32) == 0) 9.50 + printf("\n"); 9.51 + 9.52 + if (jz4730_i2c_read(i2c_channel, address, buf, 1)) 9.53 + printf("%02x ", address); 9.54 + else 9.55 + printf("?? "); 9.56 + } 9.57 + 9.58 + printf("\n"); 9.59 + for (address = 0; address < 0x20; address++) 9.60 + printf("-- "); 9.61 + printf("\n\n"); 9.62 +} 9.63 + 9.64 +/* Interpret RTC registers. */ 9.65 + 9.66 +static void rtc_datetime(uint8_t *rtcregs) 9.67 +{ 9.68 + const char *weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 9.69 + 9.70 + printf("%s %d%d-%d%d-%d%d %d%d:%d%d:%d%d\n", 9.71 + weekdays[rtcregs[0x06] & 0x07], 9.72 + (rtcregs[0x08] & 0xf0) >> 4, 9.73 + rtcregs[0x08] & 0x0f, 9.74 + (rtcregs[0x07] & 0x10) >> 4, 9.75 + rtcregs[0x07] & 0x0f, 9.76 + (rtcregs[0x05] & 0x30) >> 4, 9.77 + rtcregs[0x05] & 0x0f, 9.78 + (rtcregs[0x04] & 0x30) >> 4, 9.79 + rtcregs[0x04] & 0x0f, 9.80 + (rtcregs[0x03] & 0x70) >> 4, 9.81 + rtcregs[0x03] & 0x0f, 9.82 + (rtcregs[0x02] & 0x70) >> 4, 9.83 + rtcregs[0x02] & 0x0f); 9.84 +} 9.85 + 9.86 + 9.87 + 9.88 +int main(void) 9.89 +{ 9.90 + void *cpm; 9.91 + void *i2c, *i2c0; 9.92 + 9.93 + /* Peripheral memory. */ 9.94 + 9.95 + l4_addr_t cpm_base = 0, cpm_base_end = 0; 9.96 + l4_addr_t i2c_base = 0, i2c_base_end = 0; 9.97 + 9.98 + /* Obtain resource details describing I/O memory. */ 9.99 + 9.100 + printf("Access CPM...\n"); 9.101 + 9.102 + if (get_memory("jz4730-cpm", &cpm_base, &cpm_base_end) < 0) 9.103 + return 1; 9.104 + 9.105 + printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end); 9.106 + 9.107 + printf("Access I2C...\n"); 9.108 + 9.109 + if (get_memory("jz4730-i2c", &i2c_base, &i2c_base_end) < 0) 9.110 + return 1; 9.111 + 9.112 + printf("I2C at 0x%lx...0x%lx.\n", i2c_base, i2c_base_end); 9.113 + 9.114 + /* Obtain CPM and I2C references. */ 9.115 + 9.116 + cpm = jz4730_cpm_init(cpm_base); 9.117 + i2c = jz4730_i2c_init(i2c_base, i2c_base_end, cpm, 100000); /* 100 kHz */ 9.118 + i2c0 = jz4730_i2c_get_channel(i2c, 0); 9.119 + 9.120 + /* Enable I2C. */ 9.121 + 9.122 + jz4730_i2c_enable(i2c0); 9.123 + 9.124 + uint8_t buf[32]; 9.125 + unsigned int nwritten; 9.126 + 9.127 + /* Set the clock: 12:34:56 on Saturday 2nd January 2021. */ 9.128 + 9.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; 9.130 + nwritten = jz4730_i2c_write(i2c0, 0x51, buf, 8); 9.131 + 9.132 + printf("Written: %d\n", nwritten); 9.133 + 9.134 + /* Issue selection of device register 0. */ 9.135 + 9.136 + buf[0] = 0; 9.137 + nwritten = jz4730_i2c_write(i2c0, 0x51, buf, 1); 9.138 + 9.139 + printf("Written: %d\n", nwritten); 9.140 + 9.141 + /* Read the contents of 16 registers. */ 9.142 + 9.143 + unsigned int nread = jz4730_i2c_read(i2c0, 0x51, buf, 16); 9.144 + 9.145 + printf("Read: %d\n", nread); 9.146 + for (unsigned int i = 0; i < nread; i++) 9.147 + printf("%02x ", buf[i]); 9.148 + printf("\n"); 9.149 + 9.150 + /* Show the interpreted date and time. */ 9.151 + 9.152 + rtc_datetime(buf); 9.153 + 9.154 + /* Scan the bus. */ 9.155 + 9.156 + printf("Scan I2C0...\n"); 9.157 + i2c_scan(i2c0); 9.158 + 9.159 + return 0; 9.160 +}