diff options
Diffstat (limited to 'meta-facebook/meta-wedge/recipes-wedge/bitbang/files/src/bitbang.c')
-rw-r--r-- | meta-facebook/meta-wedge/recipes-wedge/bitbang/files/src/bitbang.c | 236 |
1 files changed, 0 insertions, 236 deletions
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bitbang/files/src/bitbang.c b/meta-facebook/meta-wedge/recipes-wedge/bitbang/files/src/bitbang.c deleted file mode 100644 index cf7dcd3..0000000 --- a/meta-facebook/meta-wedge/recipes-wedge/bitbang/files/src/bitbang.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2014-present Facebook. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -//#define DEBUG -//#define VERBOSE - -#include "bitbang.h" - -#include <errno.h> -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include "facebook/log.h" - -#define NANOSEC_IN_SEC (1000 * 1000 * 1000) - -#define BITBANG_FREQ_MAX (500 * 1000 * 1000) /* 500M Hz */ -#define BITBANG_FREQ_DEFAULT (1 * 1000 * 1000) /* 1M Hz */ - -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) - -struct bitbang_handle { - bitbang_init_st bbh_init; - uint32_t bbh_half_clk; /* ns per clock cycle */ -}; - -void bitbang_init_default(bitbang_init_st *init) -{ - memset(init, sizeof(*init), 0); - init->bbi_clk_start = BITBANG_PIN_HIGH; - init->bbi_data_out = BITBANG_CLK_EDGE_FALLING; - init->bbi_data_in = BITBANG_CLK_EDGE_RISING; - init->bbi_freq = BITBANG_FREQ_DEFAULT; -} - -bitbang_handle_st* bitbang_open(const bitbang_init_st *init) -{ - bitbang_handle_st *hdl; - - if (!init || !init->bbi_pin_f - || !init->bbi_freq || init->bbi_freq > BITBANG_FREQ_MAX) { - LOG_ERR(EINVAL, "Invalid init structure"); - return NULL; - } - - hdl = calloc(1, sizeof(*hdl)); - if (!hdl) { - return NULL; - } - - hdl->bbh_init = *init; - hdl->bbh_half_clk = NANOSEC_IN_SEC / init->bbi_freq / 2; - - LOG_DBG("Bitbang open with initial %s, data out at %s, data in at %s, " - "freq at %uHz, half clk %uns", - (init->bbi_clk_start == BITBANG_PIN_LOW) ? "LOW" : "HIGH", - (init->bbi_data_out == BITBANG_CLK_EDGE_RISING) - ? "RISING" : "FALLING", - (init->bbi_data_in == BITBANG_CLK_EDGE_RISING) - ? "RISING" : "FALLING", - init->bbi_freq, hdl->bbh_half_clk); - - return hdl; -} - -void bitbang_close(bitbang_handle_st *hdl) -{ - free(hdl); -} - -/* - * The threshold (ns) to use spin instead of nanosleep(). - * Before adding the high resolution timer support, either spin or nanosleep() - * will not bring the process wakeup within 10ms. It turns out the system time - * update is also controlled by HZ (100). - * After I added the high resolution timer support, the spin works as the - * system time is updated more frequently. However, nanosleep() solution is - * still noticable slower comparing with spin. There could be some kernel - * scheduling tweak missing. Did not get time on that yet. - * For now, use 10ms as the threshold to determine if spin or nanosleep() - * is used. - */ -#define BITBANG_SPIN_THRESHOLD (10 * 1000 * 1000) - -static int sleep_ns(uint32_t clk) -{ - struct timespec req, rem; - int rc = 0; - if (clk <= BITBANG_SPIN_THRESHOLD) { - struct timespec orig; - rc = clock_gettime(CLOCK_MONOTONIC, &req); - orig = req; - while (!rc && clk) { - uint32_t tmp; - rc = clock_gettime(CLOCK_MONOTONIC, &rem); - tmp = (rem.tv_sec - req.tv_sec) * NANOSEC_IN_SEC; - if (rem.tv_nsec >= req.tv_nsec) { - tmp += rem.tv_nsec - req.tv_nsec; - } else { - tmp -= req.tv_nsec - rem.tv_nsec; - } - if (tmp >= clk) { - break; - } - clk -= tmp; - req = rem; - } - } else { - req.tv_sec = 0; - req.tv_nsec = clk; - while ((rc = nanosleep(&req, &rem)) == -1 && errno == EINTR) { - req = rem; - } - } - if (rc == -1) { - rc = errno; - LOG_ERR(rc, "Failed to sleep %u nanoseconds", clk); - } - return rc; -} - -int bitbang_io(const bitbang_handle_st *hdl, bitbang_io_st *io) -{ - int rc = 0; - uint32_t clk = hdl->bbh_half_clk; - const struct { - bitbang_pin_value_en value; - bitbang_clk_edge_en edge; - } clks[] = { - {BITBANG_PIN_HIGH, BITBANG_CLK_EDGE_FALLING}, - {BITBANG_PIN_LOW, BITBANG_CLK_EDGE_RISING}, - }; - int clk_idx; - int n_clk = 0; - int n_bits = 0; - const uint8_t *dout = io->bbio_dout; - uint8_t *din = io->bbio_din; - int bit_pos = 7; - bitbang_pin_func pin_f = hdl->bbh_init.bbi_pin_f; - void *context = hdl->bbh_init.bbi_context; - - if ((io->bbio_in_bits == 0 && io->bbio_din) - || (io->bbio_in_bits > 0 && !io->bbio_din)) { - rc = EINVAL; - LOG_ERR(rc, "Incorrect in bits and in buffer"); - goto out; - } - - if ((io->bbio_out_bits == 0 && io->bbio_dout) - || (io->bbio_out_bits > 0 && !io->bbio_dout)) { - rc = EINVAL; - LOG_ERR(rc, "Incorrect out bits and out buffer"); - goto out; - } - - if (io->bbio_in_bits == 0 && io->bbio_out_bits == 0) { - rc = EINVAL; - LOG_ERR(rc, "Both in and out bits are 0"); - goto out; - } - - if (hdl->bbh_init.bbi_clk_start == BITBANG_PIN_HIGH) { - clk_idx = 0; - } else { - clk_idx = 1; - } - - /* set the CLK pin start position */ - pin_f(BITBANG_CLK_PIN, clks[clk_idx].value, context); - - /* clear the first byte of din */ - if (din && io->bbio_in_bits) { - memset(din, 0, (io->bbio_in_bits + 7) / 8); - } - - do { - if ((rc = sleep_ns(clk))) { - goto out; - } - - /* output first */ - if (hdl->bbh_init.bbi_data_out == clks[clk_idx].edge) { - if (dout && n_bits < io->bbio_out_bits) { - pin_f(BITBANG_DATA_OUT, (*dout >> bit_pos) & 0x1, context); - } - } - - /* then, input */ - if (hdl->bbh_init.bbi_data_in == clks[clk_idx].edge) { - if (din && n_bits < io->bbio_in_bits) { - *din |= (pin_f(BITBANG_DATA_IN, 0, context) & 0x1) << bit_pos; - } - } - - if (++n_clk % 2 == 0) { - /* one bit for every 2 half clks */ - n_bits ++; - if (bit_pos == 0) { - if (dout) { - dout++; - } - if (din) { - din++; - } - bit_pos = 7; - } else { - bit_pos --; - } - } - clk_idx = 1 - clk_idx; - pin_f(BITBANG_CLK_PIN, clks[clk_idx].value, context); - } while (n_bits < MAX(io->bbio_in_bits, io->bbio_out_bits)); - - out: - - return -rc; -} |