Landfall

pkg/landfall-examples/letux400_i2c/letux400_i2c.cc

181:04e69fba99d8
13 months ago Paul Boddie Removed superfluous clock methods. cpm-library-improvements
     1 /*     2  * Access peripherals on the I2C bus.     3  *     4  * Copyright (C) 2018, 2020 Paul Boddie <paul@boddie.org.uk>     5  *     6  * This program is free software; you can redistribute it and/or     7  * modify it under the terms of the GNU General Public License as     8  * published by the Free Software Foundation; either version 2 of     9  * the License, or (at your option) any later version.    10  *    11  * This program is distributed in the hope that it will be useful,    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    14  * GNU General Public License for more details.    15  *    16  * You should have received a copy of the GNU General Public License    17  * along with this program; if not, write to the Free Software    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,    19  * Boston, MA  02110-1301, USA    20  */    21     22 #include <l4/devices/cpm-jz4730.h>    23 #include <l4/devices/i2c-jz4730.h>    24 #include <l4/devices/memory.h>    25     26 #include <l4/re/c/util/cap_alloc.h>    27 #include <l4/sys/factory.h>    28 #include <l4/sys/icu.h>    29 #include <l4/sys/irq.h>    30 #include <l4/sys/rcv_endpoint.h>    31     32 #include <stdio.h>    33 #include <unistd.h>    34     35     36     37 /* Device and resource discovery. */    38     39 static long item_in_range(long start, long end, long index)    40 {    41   if (start < end)    42     return start + index;    43   else    44     return start - index;    45 }    46     47 /* Scan the I2C bus by performing speculative reads from each device address. */    48     49 static void i2c_scan(void *i2c_channel)    50 {    51   uint8_t buf[1];    52   unsigned int address;    53     54   for (address = 0; address < 0x20; address++)    55     printf("%02x ", address);    56   printf("\n");    57     58   for (address = 0; address < 0x20; address++)    59     printf("-- ");    60     61   for (address = 0; address < 0x80; address++)    62   {    63     if ((address % 32) == 0)    64       printf("\n");    65     66     if (jz4730_i2c_read(i2c_channel, address, buf, 1))    67       printf("%02x ", address);    68     else    69       printf("?? ");    70   }    71     72   printf("\n");    73   for (address = 0; address < 0x20; address++)    74     printf("-- ");    75   printf("\n\n");    76 }    77     78 /* Interpret RTC registers. */    79     80 static void rtc_datetime(uint8_t *rtcregs)    81 {    82   const char *weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};    83     84   printf("%s %d%d-%d%d-%d%d %d%d:%d%d:%d%d\n",    85     weekdays[rtcregs[0x06] & 0x07],    86     (rtcregs[0x08] & 0xf0) >> 4,    87     rtcregs[0x08] & 0x0f,    88     (rtcregs[0x07] & 0x10) >> 4,    89     rtcregs[0x07] & 0x0f,    90     (rtcregs[0x05] & 0x30) >> 4,    91     rtcregs[0x05] & 0x0f,    92     (rtcregs[0x04] & 0x30) >> 4,    93     rtcregs[0x04] & 0x0f,    94     (rtcregs[0x03] & 0x70) >> 4,    95     rtcregs[0x03] & 0x0f,    96     (rtcregs[0x02] & 0x70) >> 4,    97     rtcregs[0x02] & 0x0f);    98 }    99    100    101    102 int main(void)   103 {   104   void *cpm;   105   void *i2c, *i2c0;   106    107   /* Interrupts. */   108    109   l4_uint32_t i2c_irq_start = 0, i2c_irq_end = 0;   110   l4_cap_idx_t icucap, irq0cap;   111    112   /* Obtain resource details describing the interrupt for I2C channel 0. */   113    114   printf("Access IRQ...\n");   115    116   if (get_irq("jz4730-i2c", &i2c_irq_start, &i2c_irq_end) < 0)   117     return 1;   118    119   printf("IRQ range at %d...%d.\n", i2c_irq_start, i2c_irq_end);   120    121   /* Obtain capabilities for the interrupt controller and an interrupt. */   122    123   irq0cap = l4re_util_cap_alloc();   124   icucap = l4re_env_get_cap("icu");   125    126   if (l4_is_invalid_cap(icucap))   127   {    128     printf("No 'icu' capability available in the virtual bus.\n");   129     return 1;   130   }   131    132   if (l4_is_invalid_cap(irq0cap))   133   {   134     printf("Capabilities not available for interrupts.\n");   135     return 1;   136   }   137    138   /* Create interrupt objects. */   139    140   long err;   141    142   err = l4_error(l4_factory_create_irq(l4re_global_env->factory, irq0cap));   143    144   if (err)   145   {   146     printf("Could not create IRQ object: %lx\n", err);   147     return 1;   148   }   149    150   /* Bind interrupt objects to IRQ numbers. */   151    152   err = l4_error(l4_icu_bind(icucap,   153                              item_in_range(i2c_irq_start, i2c_irq_end, 0),   154                              irq0cap));   155    156   if (err)   157   {   158     printf("Could not bind IRQ to the ICU: %ld\n", err);   159     return 1;   160   }   161    162   /* Attach ourselves to the interrupt handler. */   163    164   err = l4_error(l4_rcv_ep_bind_thread(irq0cap, l4re_env()->main_thread, 0));   165    166   if (err)   167   {   168     printf("Could not attach to IRQs: %ld\n", err);   169     return 1;   170   }   171    172   /* Peripheral memory. */   173    174   l4_addr_t cpm_base = 0, cpm_base_end = 0;   175   l4_addr_t i2c_base = 0, i2c_base_end = 0;   176    177   /* Obtain resource details describing I/O memory. */   178    179   printf("Access CPM...\n");   180    181   if (get_memory("jz4730-cpm", &cpm_base, &cpm_base_end) < 0)   182     return 1;   183    184   printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end);   185    186   printf("Access I2C...\n");   187    188   if (get_memory("jz4730-i2c", &i2c_base, &i2c_base_end) < 0)   189     return 1;   190    191   printf("I2C at 0x%lx...0x%lx.\n", i2c_base, i2c_base_end);   192    193   /* Obtain CPM and I2C references. */   194    195   cpm = jz4730_cpm_init(cpm_base);   196   i2c = jz4730_i2c_init(i2c_base, i2c_base_end, cpm, 100000); /* 100 kHz */   197   i2c0 = jz4730_i2c_get_channel(i2c, 0, irq0cap);   198    199   /* Enable I2C. */   200    201   jz4730_i2c_enable(i2c0);   202    203   uint8_t buf[32];   204   unsigned int nwritten;   205    206   /* Set the clock: 12:34:56 on Saturday 2nd January 2021. */   207    208   buf[0] = 2; buf[1] = 0x56; buf[2] = 0x34; buf[3] = 0x12; buf[4] = 0x02; buf[5] = 0x06; buf[6] = 0x01; buf[7] = 0x21;   209   nwritten = jz4730_i2c_write(i2c0, 0x51, buf, 8);   210    211   printf("Written: %d\n", nwritten);   212    213   for (int i = 0; i < 3; i++)   214   {   215     /* Issue selection of device register 0. */   216    217     buf[0] = 0;   218     nwritten = jz4730_i2c_write(i2c0, 0x51, buf, 1);   219    220     printf("Written: %d\n", nwritten);   221    222     /* Read the contents of 16 registers. */   223    224     unsigned int nread = jz4730_i2c_read(i2c0, 0x51, buf, 16);   225    226     printf("Read: %d\n", nread);   227     for (unsigned int i = 0; i < nread; i++)   228       printf("%02x ", buf[i]);   229     printf("\n");   230    231     /* Show the interpreted date and time. */   232    233     rtc_datetime(buf);   234    235     /* Read from the power controller at 0x28. */   236    237     buf[0] = 0xdb;   238     nwritten = jz4730_i2c_write(i2c0, 0x28, buf, 1);   239     printf("Written: %d\n", nwritten);   240     nread = jz4730_i2c_read(i2c0, 0x28, buf, 1);   241     printf("Read: %d\n", nread);   242    243     printf("Voltage level: %1.3f\n", buf[0] * 36235 / 1000000.0);   244    245     buf[0] = 0xd9;   246     nwritten = jz4730_i2c_write(i2c0, 0x28, buf, 1);   247     printf("Written: %d\n", nwritten);   248     nread = jz4730_i2c_read(i2c0, 0x28, buf, 1);   249     printf("Read: %d\n", nread);   250    251     printf("Charger connected: %s\n", buf[0] & 1 ? "yes" : "no");   252    253     /* Scan the bus. */   254    255     printf("Scan I2C0...\n");   256     i2c_scan(i2c0);   257    258     sleep(5);   259   }   260    261   printf("start_not_possible = %d\n"   262          "read_not_ready = %d\n"   263          "read_not_ready_clear = %d\n"   264          "read_not_ready_stx = %d\n"   265          "read_not_possible = %d\n"   266          "read_nack = %d\n"   267          "read_complete = %d\n"   268          "write_not_possible = %d\n"   269          "write_complete = %d\n"   270          "total_reads = %d\n",   271          jz4730_i2c_start_not_possible(i2c0), jz4730_i2c_read_not_ready(i2c0), jz4730_i2c_read_not_ready_clear(i2c0), jz4730_i2c_read_not_ready_stx(i2c0),   272          jz4730_i2c_read_not_possible(i2c0), jz4730_i2c_read_nack(i2c0), jz4730_i2c_read_complete(i2c0),   273          jz4730_i2c_write_not_possible(i2c0), jz4730_i2c_write_complete(i2c0), jz4730_i2c_total_reads(i2c0));   274    275   sleep(30);   276    277   /* Issue a shutdown request. */   278    279   buf[0] = 0xd8; buf[1] = 1;   280   nwritten = jz4730_i2c_write(i2c0, 0x28, buf, 2);   281   printf("Written: %d\n", nwritten);   282    283   /* Detach from the interrupt. */   284    285   err = l4_error(l4_irq_detach(irq0cap));   286    287   if (err)   288     printf("Error detaching from IRQ objects: %ld\n", err);   289    290   return 0;   291 }