Ejemplo n.º 1
0
static unsigned bcm_mpi_get_clk_cfg(u32 hz, u8 cs_off_clk_cycles)
{
   u8 clk_cfg = 0;
   size_t freq_idx;

   dd_bcm_pr_debug("%s(hz=%lu, cs_off_clk_cycles=%u)\n", __func__, (unsigned long)(hz), (unsigned int)(cs_off_clk_cycles));

   /* Find the closest clock configuration */
   for (freq_idx = 0; (freq_idx < ARRAY_SIZE(bcm63xx_spi_freq_table)); freq_idx += 1) {
      if (hz >= bcm63xx_spi_freq_table[freq_idx][0]) {
         clk_cfg |= bcm63xx_spi_freq_table[freq_idx][1];
         break;
      }
   }

   /* No matching configuration found, default to lowest */
   if (freq_idx >= ARRAY_SIZE(bcm63xx_spi_freq_table)) {
      clk_cfg |= SPI_CLK_0_391MHZ;
   }

   bcm_assert(((cs_off_clk_cycles << SPI_SSOFFTIME_SHIFT) & (~(SPI_SSOFFTIME_MASK))) == 0);

   clk_cfg |= (cs_off_clk_cycles << SPI_SSOFFTIME_SHIFT);

   return (clk_cfg);
}
Ejemplo n.º 2
0
int bcm_mpi_read_write(bcm_mpi_t *t, __u8 *buf, __u8 buf_len)
{
   int ret = 0;

#ifdef BCMPH_USE_SPI_DRIVER

# ifndef BCMPH_NOHW
   struct spi_transfer tr;
   struct spi_message msg;
# endif // !BCMPH_NOHW

   dd_bcm_pr_debug("%s(buf_len=%d)\n", __func__, (int)(buf_len));

# ifndef BCMPH_NOHW
#  ifdef BCMPH_DEBUG_MPI
   bcm_mpi_add_trace(t, MPI_WRITE, buf, buf_len);
#  endif // BCMPH_DEBUG_MPI
   spi_message_init(&(msg));
   memset(&(tr), 0, sizeof(tr));
   tr.tx_buf = buf;
   tr.rx_buf = buf;
   tr.len = buf_len;
   tr.bits_per_word = 8;
   tr.speed_hz = t->mpi_clk;
   tr.cs_change = 0;
   spi_message_add_tail(&(tr), &(msg));
   ret = bcm_make_transfer(t, &(msg));
#  ifdef BCMPH_DEBUG_MPI
   bcm_mpi_add_trace(t, MPI_READ, buf, ret);
#  endif // BCMPH_DEBUG_MPI
# endif // !BCMPH_NOHW

#else // !BCMPH_USE_SPI_DRIVER

   dd_bcm_pr_debug("%s(buf_len=%d)\n", __func__, (int)(buf_len));

# ifndef BCMPH_NOHW
   bcm_assert(buf_len <= t->dev_data->fifo_size);

   if (buf_len > 0) {
#  ifdef BCMPH_DEBUG_MPI
      bcm_mpi_add_trace(t, MPI_WRITE, buf, buf_len);
#  endif // BCMPH_DEBUG_MPI
      bcm_mpi_setup_transfer(t);
      ret = bcm_mpi_rw_buf(t, buf, buf_len, true, true, NULL, 0);
#  ifdef BCMPH_DEBUG_MPI
      bcm_mpi_add_trace(t, MPI_READ, buf, ret);
#  endif // BCMPH_DEBUG_MPI
   }
   else {
      ret = 0;
   }
# endif // !BCMPH_NOHW

#endif // !BCMPH_USE_SPI_DRIVER

   return (ret);
}
Ejemplo n.º 3
0
static void bcm_timer_compute_params(bcm_timer_t *t, unsigned long period_in_usecs)
{
   unsigned long real_period;

   bcm_pr_debug("bcm_timer_compute_params(period_in_usecs=%lu)\n", (unsigned long)(period_in_usecs));

   t->period_in_jiffies = usecs_to_jiffies(period_in_usecs);
   real_period = jiffies_to_usecs(t->period_in_jiffies);
   if (real_period < period_in_usecs) {
      t->period_in_jiffies += 1;
      real_period = jiffies_to_usecs(t->period_in_jiffies);
      bcm_assert(real_period >= period_in_usecs);
   }
   t->drift_increment = real_period - period_in_usecs;
   bcm_assert((0 == t->drift_increment) || ((t->drift_increment > 0) && (t->period_in_jiffies >= 1)));

   bcm_pr_debug("one_jiffie_to_usecs = %lu, period_in_jiffies = %lu, real_period = %lu, drift_increment = %lu\n",
      (unsigned long)(one_jiffie_to_usecs), (unsigned long)(t->period_in_jiffies),
      (unsigned long)(real_period), (unsigned long)(t->drift_increment));
}
Ejemplo n.º 4
0
int __init phone_dev_le88266_init(phone_dev_le88266_t *t,
   const phone_desc_device_t *dev_desc, __u8 tick_period)
{
   int ret = 0;
   size_t line_idx;

   bcm_pr_debug("%s()\n", __func__);

   bcm_assert(ARRAY_SIZE(t->lines) <= ARRAY_SIZE(t->ve880.vdz.lines));

   bcm_assert((NULL != dev_desc) && (NULL != dev_desc->parameters.zarlink));
   for (line_idx = 0; (line_idx < dev_desc->line_count); line_idx += 1) {
      bcm_assert(NULL != dev_desc->lines[line_idx].parameters.zarlink);
   }

   do { // Empty loop
      if (dev_desc->line_count > ARRAY_SIZE(t->lines)) {
         bcm_pr_err("Le88266 description can only have %lu lines at most\n", (unsigned long)(ARRAY_SIZE(t->lines)));
         ret = -ENODEV;
         break;
      }

      ret = phone_dev_zarlink_ve880_init(&(t->ve880), &(vtbl_le88266), dev_desc, tick_period);
      if (ret) {
         break;
      }

      for (line_idx = 0; (line_idx < ARRAY_SIZE(t->lines)); line_idx += 1) {
         phone_line_init(&(t->lines[line_idx].vl));
         memset(&(t->lines[line_idx].obj), 0, sizeof(t->lines[line_idx].obj));
         memset(&(t->lines[line_idx].ctx), 0, sizeof(t->lines[line_idx].ctx));
         phone_dev_zarlink_init_line(&(t->ve880.vdz), line_idx,
            &(t->lines[line_idx].vl), &(t->lines[line_idx].obj), &(t->lines[line_idx].ctx));
      }
   }
   while (false);

   return (ret);
}
Ejemplo n.º 5
0
int __init bcm_timer_init(bcm_timer_t *t, void (*callback)(bcm_timer_t *t))
{
   int ret = 0;

   bcm_pr_debug("bcm_timer_init()\n");

   bcm_assert(NULL != callback);

   one_jiffie_to_usecs = jiffies_to_usecs(1);

   t->callback = callback;
   t->period_in_jiffies = msecs_to_jiffies(1000);

   // Init kernel timer
   init_timer(&(t->kobject));
   t->kobject.function = bcm_timer_fn;
   t->kobject.data = (unsigned long)(t);

   return (ret);
}
Ejemplo n.º 6
0
static int bcm63xx_spi_remove(struct platform_device *pdev)
{
   bcm_mpi_dev_data_t *bs = platform_get_drvdata(pdev);

   bcm_pr_debug("%s()\n", __func__);

   bcm_assert(1 == bs->ref_count);

   /* reset spi block */
   bcm_spi_writeb(bs, 0, SPI_INT_MASK);

   /* HW shutdown */
   clk_disable(bs->clk);
   devm_free_irq(&(pdev->dev), bs->irq, bs);
   devm_iounmap(&(pdev->dev), bs->regs);
   devm_release_mem_region(&(pdev->dev), bs->res_start, bs->res_size);
   platform_set_drvdata(pdev, NULL);
   clk_put(bs->clk);
   bs->ref_count = 0;

   return (0);
}
Ejemplo n.º 7
0
int __init bcm_mpi_init(bcm_mpi_t *t, const bcm_mpi_params_t *params)
{
   int ret = -1;

#ifdef BCMPH_USE_SPI_DRIVER
# ifndef BCMPH_NOHW
   struct spi_master *master;
   struct spi_board_info board_info;
# endif // !BCMPH_NOHW
#endif // BCMPH_USE_SPI_DRIVER

   bcm_pr_debug("%s()\n", __func__);
   bcm_assert(NULL != params);

#ifndef BCMPH_NOHW
   t->trx_opts.fill_byte = params->fill_byte;
   t->trx_opts.wait_completion_with_irq = params->wait_completion_with_irq;
   t->trx_opts.drop_cs_after_each_byte = params->drop_cs_after_each_byte;
   t->trx_opts.cs_off_clk_cycles = params->cs_off_clk_cycles;
#endif // !BCMPH_NOHW

#ifdef BCMPH_USE_SPI_DRIVER
   t->mpi_clk = params->clk;
# ifndef BCMPH_NOHW
   master = spi_busnum_to_master(params->bus_num);
   if (NULL == master) {
      bcm_pr_err("No SPI master found for bus num %d. Module bcm63xx-spi not loaded ?\n",
         (int)(params->bus_num));
      ret = -EINVAL;
      goto fail_master;
   }

   memset(&(board_info), 0, sizeof(board_info));
   strcpy(board_info.modalias, driver_name);
   board_info.max_speed_hz = params->clk;
   board_info.bus_num = params->bus_num;
   board_info.chip_select = params->cs;
   board_info.mode = SPI_MODE_3;
   t->dev = spi_new_device(master, &(board_info));
   if (NULL == t->dev) {
      bcm_pr_err("Failed to add SPI device (busnum = %d, chip select = %d, clock = %lu)\n",
         (int)(params->bus_num), (int)(params->cs), (unsigned long)(params->clk));
      ret = -ENOMEM;
      goto fail_new_dev;
   }
   put_device(&(master->dev));
   /* Lock the bus */
   if ((params->has_exclusive_bus_access) && (!bcm_drv_param_mpi_no_exclusive_bus_access)) {
      spi_bus_lock(t->dev->master);
      t->bus_is_locked = true;
   }

   bcm_mpi_enable_extra_CSs(params->cs);
#  ifdef BCMPH_DEBUG_MPI
   t->trace_len = 0;
#  endif // BCMPH_DEBUG_MPI

   return (0);

   spi_unregister_device(t->dev);
fail_new_dev:
   put_device(&(master->dev));
fail_master:
# else // BCMPH_NOHW
   ret = 0;
# endif // BCMPH_NOHW
#else // !BCMPH_USE_SPI_DRIVER
# ifndef BCMPH_NOHW
   t->mpi_cs = params->cs;
   t->clk_cfg = bcm_mpi_get_clk_cfg(params->clk, params->cs_off_clk_cycles);

   bcm_mpi_enable_extra_CSs(params->cs);

   if (bcm_mpi_dev_data.ref_count <= 0) {
      struct device_driver *spi_driver = driver_find(bcm63xx_spi_driver.driver.name, &platform_bus_type);
      if (NULL != spi_driver) {
         bcm_pr_err("Error: Driver '%s' is already registered, aborting...\n",
            bcm63xx_spi_driver.driver.name);
         ret = -EBUSY;
      }
      else {
         ret = platform_driver_register(&(bcm63xx_spi_driver));
      }
      bcm_assert(((ret) && (0 == bcm_mpi_dev_data.ref_count))
         || ((!ret) && (1 == bcm_mpi_dev_data.ref_count)));
   }
   else {
      bcm_mpi_dev_data.ref_count += 1;
      ret = 0;
   }
   if (!ret) {
      bcm_assert(bcm_mpi_dev_data.ref_count > 0);
      if (params->cs > bcm_mpi_dev_data.num_chipselect) {
         dev_err(&(bcm_mpi_dev_data.pdev->dev), "%s, unsupported slave %d\n",
            __func__, params->cs);
         if (1 == bcm_mpi_dev_data.ref_count) {
            platform_driver_unregister(&(bcm63xx_spi_driver));
         }
         bcm_mpi_dev_data.ref_count -= 1;
         ret = -EINVAL;
      }
      else {
         t->dev_data = &(bcm_mpi_dev_data);
      }
   }
# else // BCMPH_NOHW
   ret = 0;
# endif // BCMPH_NOHW

#endif // !BCMPH_USE_SPI_DRIVER

   return (ret);
}
Ejemplo n.º 8
0
int bcm_mpi_read(bcm_mpi_t *t, __u8 *buf, __u8 buf_len, const __u8 *prepend_buf, __u8 prepend_buf_len)
{
   int ret = 0;

#ifdef BCMPH_USE_SPI_DRIVER

# ifndef BCMPH_NOHW
   struct spi_transfer tr0;
   struct spi_transfer tr1;
   struct spi_message msg;
# endif // !BCMPH_NOHW

   dd_bcm_pr_debug("%s(buf_len=%d, prepend_buf_len=%d)\n", __func__, (int)(buf_len), (int)(prepend_buf_len));

# ifndef BCMPH_NOHW
#  ifdef BCMPH_DEBUG_MPI
   bcm_mpi_add_trace(t, MPI_WRITE, prepend_buf, prepend_buf_len);
#  endif // BCMPH_DEBUG_MPI
   spi_message_init(&(msg));
   if (prepend_buf_len > 0) {
      memset(&(tr0), 0, sizeof(tr0));
      tr0.tx_buf = prepend_buf;
      tr0.len = prepend_buf_len;
      tr0.bits_per_word = 8;
      tr0.speed_hz = t->mpi_clk;
      spi_message_add_tail(&(tr0), &(msg));
   }
   memset(&(tr1), 0, sizeof(tr1));
   tr1.rx_buf = buf;
   tr1.len = buf_len;
   tr1.bits_per_word = 8;
   tr1.speed_hz = t->mpi_clk;
   spi_message_add_tail(&(tr1), &(msg));
   ret = bcm_make_transfer(t, &(msg));
#  ifdef BCMPH_DEBUG_MPI
   bcm_mpi_add_trace(t, MPI_READ, buf, ret);
#  endif // BCMPH_DEBUG_MPI
# endif // !BCMPH_NOHW

#else // !BCMPH_USE_SPI_DRIVER

   dd_bcm_pr_debug("%s(buf_len=%d, prepend_buf_len=%d)\n", __func__, (int)(buf_len), (int)(prepend_buf_len));

# ifndef BCMPH_NOHW
   bcm_assert(buf_len <= t->dev_data->fifo_size);

#  ifdef BCMPH_DEBUG_MPI
   bcm_mpi_add_trace(t, MPI_WRITE, prepend_buf, prepend_buf_len);
#  endif // BCMPH_DEBUG_MPI
   bcm_mpi_setup_transfer(t);
   do { // Empty loop
      if (buf_len > 0) {
         if (prepend_buf_len > BCM63XX_SPI_MAX_PREPEND) {
            ret = bcm_mpi_rw_buf(t, (u8 *)(prepend_buf), prepend_buf_len, true, false, NULL, 0);
            if (ret != prepend_buf_len) {
               break;
            }
            prepend_buf = NULL;
            prepend_buf_len = 0;
         }
         ret = bcm_mpi_rw_buf(t, buf, buf_len, false, true, prepend_buf, prepend_buf_len);
      }
      else if (prepend_buf_len > 0) {
         ret = bcm_mpi_rw_buf(t, (u8 *)(prepend_buf), prepend_buf_len, true, false, NULL, 0);
      }
      else {
         ret = 0;
      }
   }
   while (0);
#  ifdef BCMPH_DEBUG_MPI
   bcm_mpi_add_trace(t, MPI_READ, buf, ret);
#  endif // BCMPH_DEBUG_MPI
# endif // !BCMPH_NOHW

#endif // !BCMPH_USE_SPI_DRIVER

   return (ret);
}
Ejemplo n.º 9
0
static int bcm_mpi_rw_buf(bcm_mpi_t *t, u8 *buf, u8 buf_len,
   bool do_tx, bool do_rx,
   const u8 *prepend_buf, u8 prepend_buf_len)
{
   bcm_mpi_dev_data_t *bs = t->dev_data;
   u16 msg_ctl;
   u16 cmd;
   unsigned int timeout;
   u8 rx_tail;

   dd_bcm_pr_debug("%s(buf_len=%u, do_tx=%d, do_rx=%d, prepend_buf_len=%u)\n",
      __func__, (unsigned int)(buf_len), (int)(do_tx), (int)(do_rx), (unsigned int)(prepend_buf_len));

   /* Disable the CMD_DONE interrupt */
   bcm_spi_writeb(bs, 0, SPI_INT_MASK);

   cmd = SPI_CMD_START_IMMEDIATE;
   cmd |= (t->mpi_cs << SPI_CMD_DEVICE_ID_SHIFT);
   if (t->trx_opts.drop_cs_after_each_byte) {
      cmd |= (1 << SPI_CMD_ONE_BYTE_SHIFT);
   }

   if (do_tx) {
      bcm_assert((0 == prepend_buf_len) && (buf_len > 0));
      memcpy_toio(bs->tx_io, buf, buf_len);
   }
   else {
      bcm_assert(do_rx);
      if (prepend_buf_len > 0) {
         memcpy_toio(bs->tx_io, prepend_buf, prepend_buf_len);
         cmd |= (prepend_buf_len << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
      }
      else {
         bcm_assert(buf_len > 0);
      }
   }

   if (t->trx_opts.wait_completion_with_irq) {
      init_completion(&(bs->done));
   }

   /* Fill in the Message control register */
   msg_ctl = (buf_len << SPI_BYTE_CNT_SHIFT);

   if (do_tx) {
      if (do_rx) {
         msg_ctl |= (SPI_FD_RW << bs->msg_type_shift);
      }
      else {
         msg_ctl |= (SPI_HD_W << bs->msg_type_shift);
      }
   }
   else {
      msg_ctl |= (SPI_HD_R << bs->msg_type_shift);
   }

   switch (bs->msg_ctl_width) {
      case 8:
         bcm_spi_writeb(bs, msg_ctl, SPI_MSG_CTL);
         break;
      case 16:
         bcm_spi_writew(bs, msg_ctl, SPI_MSG_CTL);
         break;
      default:
         bcm_assert(0);
         break;
   }

   bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
   if (t->trx_opts.wait_completion_with_irq) {
      /* Enable the CMD_DONE interrupt */
      bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
   }

   /* Issue the transfer */
   bcm_spi_writew(bs, cmd, SPI_CMD);

   if (t->trx_opts.wait_completion_with_irq) {
      timeout = wait_for_completion_timeout(&bs->done, HZ);
      if (!timeout) {
         return (-ETIMEDOUT);
      }
   }
   else {
      while (!(bcm_spi_readb(bs, SPI_INT_STATUS) & SPI_INTR_CMD_DONE))
      {
      }
   }

   if (do_rx) {
      /* read out all data */
      rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
      if (rx_tail != buf_len) {
         return (-EINVAL);
      }
      if (rx_tail > 0) {
         memcpy_fromio(buf, bs->rx_io, buf_len);
      }
   }

   return (buf_len);
}