A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 249 lines 5.8 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2006 by Linus Nielsen Feltzing 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21#include "config.h" 22#include "cpu.h" 23#include <stdbool.h> 24#include <stdlib.h> 25#include "debug.h" 26#include "generic_i2c.h" 27 28#define MAX_I2C_INTERFACES 5 29 30static int i2c_num_ifs = 0; 31static const struct i2c_interface *i2c_if[MAX_I2C_INTERFACES]; 32 33static void i2c_start(const struct i2c_interface *iface) 34{ 35 iface->sda_dir(true); 36 37 iface->sda_out(1); 38 iface->scl_out(1); 39 iface->delay(iface->delay_su_sta); 40 iface->sda_out(0); 41 iface->delay(iface->delay_hd_sta); 42 iface->scl_out(0); 43 iface->delay(iface->delay_hd_dat); 44} 45 46static void i2c_stop(const struct i2c_interface *iface) 47{ 48 iface->sda_dir(true); 49 50 iface->sda_out(0); 51 iface->delay(iface->delay_su_dat); 52 iface->scl_out(1); 53 iface->delay(iface->delay_su_sto); 54 iface->sda_out(1); 55} 56 57static void i2c_ack(const struct i2c_interface *iface, bool ack) 58{ 59 iface->sda_dir(true); 60 iface->sda_out(!ack); 61 iface->delay(iface->delay_su_dat); 62 iface->scl_out(1); 63 iface->delay(iface->delay_thigh); 64 iface->scl_out(0); 65 iface->delay(iface->delay_hd_dat); 66} 67 68static int i2c_getack(const struct i2c_interface *iface) 69{ 70 int ret = 1; 71 72 iface->sda_dir(false); 73 iface->delay(iface->delay_su_dat); 74 iface->scl_out(1); 75 iface->delay(iface->delay_thigh); 76 if (iface->sda_in()) 77 ret = 0; /* ack failed */ 78 iface->scl_out(0); 79 iface->delay(iface->delay_hd_dat); 80 return ret; 81} 82 83static unsigned char i2c_inb(const struct i2c_interface *iface, bool ack) 84{ 85 int i; 86 unsigned char byte = 0; 87 88 iface->sda_dir(false); 89 90 /* clock in each bit, MSB first */ 91 for ( i=0x80; i; i>>=1 ) { 92 iface->delay(iface->delay_su_dat); 93 iface->scl_out(1); 94 iface->delay(iface->delay_thigh); 95 if (iface->sda_in()) 96 byte |= i; 97 iface->scl_out(0); 98 iface->delay(iface->delay_hd_dat); 99 } 100 101 i2c_ack(iface, ack); 102 103 return byte; 104} 105 106static int i2c_outb(const struct i2c_interface *iface, unsigned char byte) 107{ 108 int i; 109 110 iface->sda_dir(true); 111 112 /* clock out each bit, MSB first */ 113 for (i=0x80; i; i>>=1) { 114 iface->sda_out(i & byte); 115 iface->delay(iface->delay_su_dat); 116 iface->scl_out(1); 117 iface->delay(iface->delay_thigh); 118 iface->scl_out(0); 119 iface->delay(iface->delay_hd_dat); 120 } 121 122 return i2c_getack(iface); 123} 124 125int i2c_write_data(int bus_index, int bus_address, int address, 126 const unsigned char* buf, int count) 127{ 128 int i; 129 int ret = 0; 130 const struct i2c_interface *iface = i2c_if[bus_index]; 131 132 i2c_start(iface); 133 if (!i2c_outb(iface, bus_address & 0xfe)) 134 { 135 ret = -2; 136 goto end; 137 } 138 139 if (address != -1) 140 { 141 if (!i2c_outb(iface, address)) 142 { 143 ret = -3; 144 goto end; 145 } 146 } 147 148 for(i = 0;i < count;i++) 149 { 150 if (!i2c_outb(iface, buf[i])) 151 { 152 ret = -4; 153 break; 154 } 155 } 156 157end: 158 i2c_stop(iface); 159 return ret; 160} 161 162int i2c_read_data(int bus_index, int bus_address, int address, 163 unsigned char* buf, int count) 164{ 165 int i; 166 int ret = 0; 167 const struct i2c_interface *iface = i2c_if[bus_index]; 168 169 if (address != -1) 170 { 171 i2c_start(iface); 172 if (!i2c_outb(iface, bus_address & 0xfe)) 173 { 174 ret = -2; 175 goto end; 176 } 177 if (!i2c_outb(iface, address)) 178 { 179 ret = -3; 180 goto end; 181 } 182 } 183 184 i2c_start(iface); 185 if (!i2c_outb(iface, bus_address | 1)) 186 { 187 ret = -4; 188 goto end; 189 } 190 191 for(i = 0;i < count-1;i++) 192 buf[i] = i2c_inb(iface, true); 193 194 buf[i] = i2c_inb(iface, false); 195 196end: 197 i2c_stop(iface); 198 return ret; 199} 200 201int i2c_write_read_data(int bus_index, int bus_address, 202 const unsigned char* buf_write, int count_write, 203 unsigned char* buf_read, int count_read) 204{ 205 int i; 206 int ret = 0; 207 const struct i2c_interface *iface = i2c_if[bus_index]; 208 209 i2c_start(iface); 210 if (!i2c_outb(iface, bus_address)) 211 { 212 ret = -2; 213 goto end; 214 } 215 216 for(i = 0;i < count_write;i++) 217 { 218 if (!i2c_outb(iface, buf_write[i])) 219 { 220 ret = -3; 221 goto end; 222 } 223 } 224 225 for(i = 0;i < count_read-1;i++) 226 buf_read[i] = i2c_inb(iface, true); 227 228 buf_read[i] = i2c_inb(iface, false); 229 230end: 231 i2c_stop(iface); 232 return ret; 233} 234 235/* returns bus index which can be used as a handle, or <0 on error */ 236int i2c_add_node(const struct i2c_interface *iface) 237{ 238 int bus_index; 239 240 if (i2c_num_ifs == MAX_I2C_INTERFACES) 241 return -1; 242 243 bus_index = i2c_num_ifs++; 244 i2c_if[bus_index] = iface; 245 246 iface->scl_dir(true); 247 248 return bus_index; 249}