# HG changeset patch # User Paul Boddie # Date 1579964838 -3600 # Node ID 88f792e6a5037bcce3b8af32a4905730937e8856 # Parent 6a5b49213ca2737f6676ec342d31de841fb158a8 Removed DDC access which is unreliable (and perhaps better performed using the HDMI peripheral anyway), introducing PMIC and RTC access. diff -r 6a5b49213ca2 -r 88f792e6a503 pkg/landfall-examples/ci20_i2c/ci20_i2c.c --- a/pkg/landfall-examples/ci20_i2c/ci20_i2c.c Wed Jul 24 00:54:00 2019 +0200 +++ b/pkg/landfall-examples/ci20_i2c/ci20_i2c.c Sat Jan 25 16:07:18 2020 +0100 @@ -1,7 +1,7 @@ /* * (c) 2008-2009 Adam Lackorzynski * economic rights: Technische Universität Dresden (Germany) - * Copyright (C) 2017, 2018, 2019 Paul Boddie + * Copyright (C) 2017, 2018, 2019, 2020 Paul Boddie * * This file is part of TUD:OS and distributed under the terms of the * GNU General Public License 2. @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -55,29 +54,6 @@ return start - index; } -static void show_deviceid(uint8_t buf[]) -{ - printf("Manufacturer %x part %x revision %x\n", - (buf[0] << 4) | (buf[1] >> 4), - ((buf[1] & 0xf) << 5) | (buf[2] >> 3), - buf[2] & 0x7); -} - -static void show_data(uint8_t buf[], unsigned pos) -{ - unsigned i; - - if (pos) - { - printf("Read %d bytes from bus.\n", pos); - for (i = 0; i < pos; i++) - printf(" %02x", buf[i]); - printf("\n"); - } - else - printf("No reply from bus.\n"); -} - static long i2c_read(void *i2c_channel, uint8_t *buf, unsigned length, l4_cap_idx_t irqcap) { @@ -126,15 +102,34 @@ return jz4780_i2c_have_written(i2c_channel); } -static long i2c_get(void *i2c_channel, uint8_t reg, uint8_t *buffer, long length, l4_cap_idx_t irqcap) +static long i2c_get(void *i2c_channel, uint8_t *buffer, long length, l4_cap_idx_t irqcap) { long pos; + memset(buffer, 0, length); + pos = i2c_read(i2c_channel, buffer, length, irqcap); + + jz4780_i2c_stop(i2c_channel); + + return pos; +} + +static long i2c_get_reg(void *i2c_channel, uint8_t reg, uint8_t *buffer, long length, l4_cap_idx_t irqcap) +{ buffer[0] = reg; i2c_write(i2c_channel, buffer, 1, irqcap); - memset(buffer, 0, length); - pos = i2c_read(i2c_channel, buffer, length, irqcap); + return i2c_get(i2c_channel, buffer, length, irqcap); +} + +static long i2c_set_reg(void *i2c_channel, uint8_t reg, uint8_t *buffer, long length, l4_cap_idx_t irqcap) +{ + uint8_t buf[length + 1]; + long pos; + + buf[0] = reg; + memcpy(buf + 1, buffer, length); + pos = i2c_write(i2c_channel, buf, length + 1, irqcap); jz4780_i2c_stop(i2c_channel); @@ -172,7 +167,7 @@ printf("\n"); jz4780_i2c_set_target(i2c_channel, address); - i2c_get(i2c_channel, 0, buf, 1, irqcap); + i2c_get(i2c_channel, buf, 1, irqcap); if (!jz4780_i2c_failed(i2c_channel)) printf("%02x ", address); @@ -186,82 +181,56 @@ printf("\n\n"); } -static void ddc_read(void *i2c_channel, l4_cap_idx_t irqcap) +static void pmic_dump(void *i2c_channel, l4_cap_idx_t irqcap) { - /* Buffer for reading. */ - - uint8_t buf[128]; + uint8_t regs[] = {0x00, 0x01, 0x10, 0x12, 0x20, 0x22, 0x30, 0x32, + 0x40, 0x41, 0x50, 0x51, 0x60, 0x61, 0x70, 0x71, + 0x80, 0x81, 0x91}; + uint8_t buf[1]; long pos; - - /* DDC EDID details. */ - - unsigned width = 0, height = 0; - - printf("Trying DDC on I2C4...\n"); - - /* Attempt to read from address 0x50 for DDC. - See: drivers/video/fbdev/core/fb_ddc.c */ + unsigned i; - jz4780_i2c_set_target(i2c_channel, 0x50); - pos = i2c_get(i2c_channel, 0, buf, 128, irqcap); - - if (pos <= 0) + for (i = 0; i < sizeof(regs); i++) { - printf("Read failed.\n"); - return; + printf("PMIC %02x:\n", regs[i]); + jz4780_i2c_set_target(i2c_channel, 0x5a); + pos = i2c_get_reg(i2c_channel, regs[i], buf, 1, irqcap); + i2c_report(i2c_channel, buf, pos); } - - show_data(buf, pos); - - /* Attempt to decode EDID information. */ - - libedid_prefered_resolution(buf, &width, &height); - printf("Preferred resolution: %d x %d\n", width, height); - - libedid_dump_standard_timings(buf); } -static void pmic_out3_control(void *i2c_channel, l4_cap_idx_t irqcap) +static void rtc_dump(void *i2c_channel, l4_cap_idx_t irqcap, uint8_t *rtcregs) { - /* Buffer for communicating. */ - - uint8_t buf[2]; - - /* Attempt to read from address 0x5a for PMIC OUT3. */ - - jz4780_i2c_set_target(i2c_channel, 0x5a); - i2c_get(i2c_channel, 0x32, buf, 1, irqcap); - i2c_report(i2c_channel, buf, 1); - -#if 0 - /* Disable the regulator. */ - - printf("Updating...\n"); - - buf[1] = buf[0] & ~0x80; - buf[0] = 0x32; - i2c_write(i2c_channel, buf, 2, irqcap); - jz4780_i2c_stop(i2c_channel); - - /* Read back from the register. Seemed to give 0xff, which makes no real - sense, although the regulator did bring the voltage level low. */ - - i2c_get(i2c_channel, 0x32, buf, 1, irqcap); - i2c_report(i2c_channel, buf, 1); -#endif -} - -static void rtc_control(void *i2c_channel, l4_cap_idx_t irqcap) -{ - /* Buffer for communicating. */ - - uint8_t buf[1]; - /* Attempt to read from address 0x51 for RTC. */ jz4780_i2c_set_target(i2c_channel, 0x51); - i2c_get(i2c_channel, 0x0f, buf, 1, irqcap); - i2c_report(i2c_channel, buf, 1); + i2c_get_reg(i2c_channel, 0x00, rtcregs, 16, irqcap); + i2c_report(i2c_channel, rtcregs, 16); +} + +static void rtc_datetime(uint8_t *rtcregs) +{ + char *weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; + printf("%s %d%d-%d%d-%d%d %d%d:%d%d:%d%d\n", + weekdays[rtcregs[0x06] & 0x07], + (rtcregs[0x08] & 0xf0) >> 4, + rtcregs[0x08] & 0x0f, + (rtcregs[0x07] & 0x10) >> 4, + rtcregs[0x07] & 0x0f, + (rtcregs[0x05] & 0x30) >> 4, + rtcregs[0x05] & 0x0f, + (rtcregs[0x04] & 0x30) >> 4, + rtcregs[0x04] & 0x0f, + (rtcregs[0x03] & 0x70) >> 4, + rtcregs[0x03] & 0x0f, + (rtcregs[0x02] & 0x70) >> 4, + rtcregs[0x02] & 0x0f); +} + +static int rtc_update(void *i2c_channel, l4_cap_idx_t irqcap, uint8_t *rtcregs) +{ + jz4780_i2c_set_target(i2c_channel, 0x51); + return i2c_set_reg(i2c_channel, 0x02, rtcregs + 2, 7, irqcap); } int main(void) @@ -275,11 +244,10 @@ l4_addr_t cpm_base = 0, cpm_base_end = 0; l4_addr_t port_d, port_d_end; l4_addr_t port_e, port_e_end; - l4_addr_t port_f, port_f_end; /* Peripheral abstractions. */ - void *gpio_port_d, *gpio_port_e, *gpio_port_f; + void *gpio_port_d, *gpio_port_e; void *i2c, *cpm; void *i2c0, *i2c4; @@ -288,6 +256,11 @@ l4_uint32_t i2c_irq_start = 0, i2c_irq_end = 0; l4_cap_idx_t icucap, irq0cap, irq4cap; + /* RTC registers. */ + + uint8_t rtcregs[16]; + int i; + /* Obtain capabilities for the interrupt controller and an interrupt. */ irq0cap = l4re_util_cap_alloc(); @@ -381,27 +354,20 @@ port_d_end = port_d + 0x100; port_e = gpio_base + 0x400; port_e_end = port_e + 0x100; - port_f = gpio_base + 0x500; - port_f_end = port_f + 0x100; printf("PORTD at 0x%lx...0x%lx.\n", port_d, port_d_end); printf("PORTE at 0x%lx...0x%lx.\n", port_e, port_e_end); - printf("PORTF at 0x%lx...0x%lx.\n", port_f, port_f_end); gpio_port_d = jz4780_gpio_init(port_d, port_d_end, 32, 0xffff4fff, 0x0000b000); gpio_port_e = jz4780_gpio_init(port_e, port_e_end, 32, 0xfffff37c, 0x00000483); - gpio_port_f = jz4780_gpio_init(port_f, port_f_end, 32, 0x7fa7f00f, 0x00580ff0); printf("Set up GPIO pins...\n"); jz4780_gpio_config_pad(gpio_port_d, PMSCL, Function_alt, 0); jz4780_gpio_config_pad(gpio_port_d, PMSDA, Function_alt, 0); - //jz4780_gpio_config_pad(gpio_port_e, RTCSCL, Function_alt, 1); - //jz4780_gpio_config_pad(gpio_port_e, RTCSDA, Function_alt, 1); - - jz4780_gpio_config_pad(gpio_port_f, DDCSCL, Function_alt, 1); - jz4780_gpio_config_pad(gpio_port_f, DDCSDA, Function_alt, 1); + jz4780_gpio_config_pad(gpio_port_e, RTCSCL, Function_alt, 1); + jz4780_gpio_config_pad(gpio_port_e, RTCSDA, Function_alt, 1); /* Obtain CPM and I2C objects. */ @@ -424,11 +390,28 @@ printf("Scan I2C4...\n"); i2c_scan(i2c4, irq4cap); - pmic_out3_control(i2c0, irq0cap); + printf("PMIC...\n"); + pmic_dump(i2c0, irq0cap); + + printf("RTC...\n"); + rtc_dump(i2c4, irq4cap, rtcregs); - ddc_read(i2c4, irq4cap); + rtcregs[0x02] = 0x56; + rtcregs[0x03] = 0x34; + rtcregs[0x04] = 0x12; + rtcregs[0x05] = 0x25; /* 25th */ + rtcregs[0x06] = 0x06; /* Saturday */ + rtcregs[0x07] = 0x01; /* January */ + rtcregs[0x08] = 0x20; /* 2020 */ - //rtc_control(i2c4, irq4cap); + printf("Updated %d registers.\n", rtc_update(i2c4, irq4cap, rtcregs)); + + for (i = 0; i < 10; i++) + { + rtc_dump(i2c4, irq4cap, rtcregs); + rtc_datetime(rtcregs); + sleep(1); + } jz4780_i2c_disable(i2c0); jz4780_i2c_disable(i2c4);