int main()

in common/recipes-utils/bitbang/files/src/mdio_bb.c [85:337]


int main(int argc, char* const argv[])
{
  int opt;
  int mdc = -1, mdio = -1;
  bitbang_pin_value_en mdc_start = BITBANG_PIN_HIGH;
  bitbang_clk_edge_en out_edge = BITBANG_CLK_EDGE_FALLING;
  bitbang_clk_edge_en in_edge = BITBANG_CLK_EDGE_RISING;
  int is_write;
  uint32_t phy_addr;
  uint32_t reg_addr;
  uint32_t data;                /* data to write/read*/
  uint8_t buf[N_BYTES];
  uint8_t *buf_p;
  mdio_context_st ctx;
  bitbang_init_st init;
  bitbang_handle_st *hdl = NULL;
  bitbang_io_st io;
  int n_bits;
  int i;
  int rc = 0;
  int preamble = 0;
  int binary = 0;

  while ((opt = getopt(argc, argv, "bc:C:d:D:p")) != -1) {
    switch (opt) {
    case 'b':
      binary = 1;
      break;
    case 'c':
      mdc = atoi(optarg);
      break;
    case 'C':
      if (!strcasecmp(optarg, "high")) {
        mdc_start = BITBANG_PIN_HIGH;
      } else if (!strcasecmp(optarg, "low")) {
        mdc_start = BITBANG_PIN_LOW;
      } else {
        usage();
        exit(-1);
      }
      break;
    case 'd':
      mdio = atoi(optarg);
      break;
    case 'I':
      if (!strcasecmp(optarg, "rising")) {
        in_edge = BITBANG_CLK_EDGE_RISING;
      } if (!strcasecmp(optarg, "falling")) {
        in_edge = BITBANG_CLK_EDGE_FALLING;
      } else {
        usage();
        exit(-1);
      }
      break;
    case 'O':
      if (!strcasecmp(optarg, "rising")) {
        out_edge = BITBANG_CLK_EDGE_RISING;
      } if (!strcasecmp(optarg, "falling")) {
        out_edge = BITBANG_CLK_EDGE_FALLING;
      } else {
        usage();
        exit(-1);
      }
      break;
    case 'p':
      preamble = 1;
      break;
    default:
      usage();
      exit(-1);
    }
  }

  if (mdc < 0 || mdio < 0) {
    usage();
    exit(-1);
  }

  if (optind + 2 >= argc) {
    usage();
    exit(-1);
  }

  /* read or write */
  if (!strcasecmp(argv[optind], "read")) {
    is_write = 0;
  } else if (!strcasecmp(argv[optind], "write")) {
    is_write = 1;
  } else {
    usage();
    exit(-1);
  }

  /* phy address, 5 bits only, so must be <= 0x1f */
  phy_addr = strtoul(argv[optind + 1], NULL, 0);
  if (phy_addr > 0x1f) {
    usage();
    exit(-1);
  }

  /* register address, 5 bits only, so must be <= 0x1f */
  reg_addr = strtoul(argv[optind + 2], NULL, 0);
  if (reg_addr > 0x1f) {
    usage();
    exit(-1);
  }

  /* data */
  if (is_write) {
    if ((!binary && (optind + 4 != argc)) ||
        (binary && (optind + 3 != argc))) {
      usage();
      exit(-1);
    }
    if (binary) {
      uint16_t temp = 0;
      if (fread(&temp, sizeof(temp), 1, stdin) != 1) {
        usage();
        exit(-1);
      }
      data = htons(temp);
    } else {
      data = strtoul(argv[optind + 3], NULL, 0);
    }
    if (data > 0xFFFF) {
      usage();
      exit(-1);
    }
  } else {
    if ((!binary && (optind + 3 != argc)) ||
        (binary && (optind + 2 != argc))) {
      usage();
      exit(-1);
    }
  }

  /* open all gpio */
  memset(&ctx, 0, sizeof(ctx));
  gpio_init_default(&ctx.m_mdc);
  gpio_init_default(&ctx.m_mdio);
  if (gpio_open(&ctx.m_mdc, mdc) || gpio_open(&ctx.m_mdio, mdio)) {
    goto out;
  }

  if (gpio_change_direction(&ctx.m_mdc, GPIO_DIRECTION_OUT)
      || gpio_change_direction(&ctx.m_mdio, GPIO_DIRECTION_OUT)) {
    goto out;
  }

  bitbang_init_default(&init);
  init.bbi_clk_start = mdc_start;
  init.bbi_data_out = out_edge;
  init.bbi_data_in = in_edge;
  init.bbi_freq = 1000 * 1000;   /* 1M Hz */
  init.bbi_pin_f = mdio_pin_f;
  init.bbi_context = &ctx;
  hdl = bitbang_open(&init);
  if (!hdl) {
    goto out;
  }

  if (is_write) {
    buf[0] = (data >> 8) & 0xFF;
    buf[1] = data & 0xFF;
    io.bbio_out_bits = 16;
    io.bbio_dout = buf;
    io.bbio_in_bits = 0;
    io.bbio_din = NULL;
  } else {
    io.bbio_in_bits = 16;
    io.bbio_din = buf;
    io.bbio_out_bits = 0;
    io.bbio_dout = NULL;
  }

  /* preamble, 32b */
  buf_p = buf;
  n_bits = 0;
  if (preamble) {
    /* 32 bit of 1 for preamble */
    for (i = 0; i < 4; i++) {
      *buf_p++ = 0xFF;
    }
    n_bits += 32;
  }

  /*
   * MDIO transaction header is:
   * 2b START, 2b OPER CODE, 5b PHY ADDR, 5b register addr, 2b TURNROUND
   */
  *buf_p++ = (START_OF_FRAME << 6) | (((is_write) ? OP_WRITE : OP_READ) << 4)
    | ((phy_addr >> 1) & 0xF);
  *buf_p++ = ((phy_addr & 0x1) << 7) | ((reg_addr & 0x1F) << 2) | TURNAROUND;
  if (is_write) {
    *buf_p++ = (data >> 8) & 0xFF;
    *buf_p++ = data & 0xFF;
    /* total # of bits is transaction header + 2 bytes to write */
    n_bits += 2 + 2 + 5 + 5 + 2 + 16;
  } else {
    /* for read, master does not send TR, so, n_bits should not include TR */
    n_bits += 2 + 2 + 5 + 5;
  }

  memset(&io, 0, sizeof(io));
  io.bbio_out_bits = n_bits;
  io.bbio_dout = buf;
  io.bbio_in_bits = 0;
  io.bbio_din = NULL;

  rc = bitbang_io(hdl, &io);
  if (rc != 0) {
    goto out;
  }

  /* for read, need to do another io for (2b TR + 16b data) reading */
  if (!is_write) {
    /* first, change the MDIO to input */
    gpio_change_direction(&ctx.m_mdio, GPIO_DIRECTION_IN);
    /* then, run the clock for read */
    memset(&io, 0, sizeof(io));
    io.bbio_out_bits = 0;
    io.bbio_dout = NULL;;
    io.bbio_in_bits = 18;
    io.bbio_din = buf;

    rc = bitbang_io(hdl, &io);
    if (rc != 0) {
      goto out;
    }

    data = ((buf[0] << 2) | (buf[1] >> 6)) & 0xFF;
    data <<= 8;
    data |= ((buf[1] << 2) | (buf[2] >> 6)) & 0xFF;
  }

  if (binary) {
    if (!is_write) {
      uint16_t temp = ntohs(data);
      fwrite(&temp, sizeof(temp), 1, stdout);
    }
  } else {
    printf("%s: 0x%02x\n", (is_write) ? "Wrote" : "Read", data);
  }

 out:
  if (hdl) {
    bitbang_close(hdl);
  }
  gpio_close(&ctx.m_mdc);
  gpio_close(&ctx.m_mdio);

  return 0;
}