linux/drivers/spi/spi-xcomm.c
<<
>>
Prefs
   1/*
   2 * Analog Devices AD-FMCOMMS1-EBZ board I2C-SPI bridge driver
   3 *
   4 * Copyright 2012 Analog Devices Inc.
   5 * Author: Lars-Peter Clausen <lars@metafoo.de>
   6 *
   7 * Licensed under the GPL-2 or later.
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/init.h>
  12#include <linux/module.h>
  13#include <linux/delay.h>
  14#include <linux/i2c.h>
  15#include <linux/spi/spi.h>
  16#include <asm/unaligned.h>
  17
  18#define SPI_XCOMM_SETTINGS_LEN_OFFSET           10
  19#define SPI_XCOMM_SETTINGS_3WIRE                BIT(6)
  20#define SPI_XCOMM_SETTINGS_CS_HIGH              BIT(5)
  21#define SPI_XCOMM_SETTINGS_SAMPLE_END           BIT(4)
  22#define SPI_XCOMM_SETTINGS_CPHA                 BIT(3)
  23#define SPI_XCOMM_SETTINGS_CPOL                 BIT(2)
  24#define SPI_XCOMM_SETTINGS_CLOCK_DIV_MASK       0x3
  25#define SPI_XCOMM_SETTINGS_CLOCK_DIV_64         0x2
  26#define SPI_XCOMM_SETTINGS_CLOCK_DIV_16         0x1
  27#define SPI_XCOMM_SETTINGS_CLOCK_DIV_4          0x0
  28
  29#define SPI_XCOMM_CMD_UPDATE_CONFIG     0x03
  30#define SPI_XCOMM_CMD_WRITE             0x04
  31
  32#define SPI_XCOMM_CLOCK 48000000
  33
  34struct spi_xcomm {
  35        struct i2c_client *i2c;
  36
  37        uint16_t settings;
  38        uint16_t chipselect;
  39
  40        unsigned int current_speed;
  41
  42        uint8_t buf[63];
  43};
  44
  45static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len)
  46{
  47        uint16_t settings;
  48        uint8_t *buf = spi_xcomm->buf;
  49
  50        settings = spi_xcomm->settings;
  51        settings |= len << SPI_XCOMM_SETTINGS_LEN_OFFSET;
  52
  53        buf[0] = SPI_XCOMM_CMD_UPDATE_CONFIG;
  54        put_unaligned_be16(settings, &buf[1]);
  55        put_unaligned_be16(spi_xcomm->chipselect, &buf[3]);
  56
  57        return i2c_master_send(spi_xcomm->i2c, buf, 5);
  58}
  59
  60static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,
  61        struct spi_device *spi, int is_active)
  62{
  63        unsigned long cs = spi->chip_select;
  64        uint16_t chipselect = spi_xcomm->chipselect;
  65
  66        if (is_active)
  67                chipselect |= BIT(cs);
  68        else
  69                chipselect &= ~BIT(cs);
  70
  71        spi_xcomm->chipselect = chipselect;
  72}
  73
  74static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
  75        struct spi_device *spi, struct spi_transfer *t, unsigned int *settings)
  76{
  77        unsigned int speed;
  78
  79        if ((t->bits_per_word && t->bits_per_word != 8) || t->len > 62)
  80                return -EINVAL;
  81
  82        speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
  83
  84        if (speed != spi_xcomm->current_speed) {
  85                unsigned int divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, speed);
  8685" class="line" namif (s15* Author:="drivers/spi/spi-m.c#L77" id="L77" class8"line8 name="L67">  67         , unsigned int *SPI_XCOMM_SETTINGS_Cref">speed);
  67  68BIT(6)
  69         , unsigned int *SPI_XCOMM_SETTINGS_Cref">speed);
  80  68        else
  69         , unsigned int *SPI_XCOMM_SETTINGS_ref">speed);
  52
  69 ">speed != spi_xcomm->cu>chipselect = speed;
 ="L72">  72}
  65
  66        if (spi-><>de=max_speed_hz">">bits_peripselect |= BIT(6)
  67 , unsigned int *SPI_XCOMM_SEsref">speed;
  68        else
  69 , unsigned int *SPI_XCOMM_SEsref">speed;
  65
  66        if (spi-><>de=max_speed_hz">">bits_peripselect |= BIT(6)
  69 , unsigned int *SPI_XCOMM_SEsref">speed;
  68        else
  67 , unsigned int *SPI_XCOMM_SEsref">speed;
  65
  66        if (spi-><>de=max_speed_hz">">bits_peripselect |= BIT(6)
  67 , unsigned int *SPI_XCOMM_SETsref">speed;
  68        else
  69 , unsigned int *SPI_XCOMM_SETsref">speed;
  65
        0sref">speed;
  72}
  83
  74static int spi_xcomm *spi_xcomm,
  75        struct spi_device *spi, struct spi_transfer *BIT(6)
  76{
   74static int respeed;
  78
  79 ? t->tx_bufa href="+code=t"x_buf">current_speed) {
  80 ">speed != spi_xcomm->buf[0] = SPI_XCOMx/init.h>
  69 f">spi->DIV_ROUND_UP(spi_xcomm->, t->tx_bufa href="+code=t"x_buf">cuXCOMM_CLOCK, t->>
  52
  69 ">speed != rebuf[0] = i2c_master_send(spi_xcomm->i2c, spi_xcomm->, t->>
  67  79 ? rele0sref">BIT(6)
  85 ="L66">        static int respeed;
  8685" c 68speed != t->speed;
  67                        return -speed;
 }c 68t->rx_bufa href="+code=trx_buf">current_speed) {
  69                rebuf[0] = spi_xcomm->i2c, t->rx_bufa href="+code=trx_buf">cuXCOMM_CLOCK, t->>
  80  79 ? rele0sref">BIT(6)
  69                static int respeed;
  69  68speed != t->BIT(6)
  69                        return -speed;
 ="L72">  72}
  65
        static int t->speed;
  72}
  78
  74static int <_setup_transfer(struct spi_transfer *ass="sprcode=settingsass="sf">s">spi_xcomm,
 p_transfer(struct spi_transfer *ascomm_sync_configasclasssref">BIT(6)
) {
 p_transfer(struct spi_xcomm *s=x/init.h>
  63    74static int settings = spi_xcomm->settings;
 p_transfer(struct spi_device *settings = ascomm_sync_configasclassss="sref">t->settings;
  63  ref">t->cs_chang0sref">speed;
 p_transfer(struct spi_transfer *speed;
  47        boolhref="+code=buf"oolname=_xcomm->settings = _trspeed;
   74static int <"L7u="+code=settings""L7u=lassf">0sref">speed;
  47        boolhref="+code=buf"oolname=_xcomm->speed;
  65
  51        settings = _trspeed;
  52
  53        "a href="+code=spi_xcomm_chipselect" class="sref">spi_xcomm_spi_xcomm *speed_hz : , >
  44
  55        list_for_each_entryde=max_speed_hzlist_for_each_entrycomm_spi_xcomm *, &ascomm_sync_configasclassss="sref">t->ass="sre="+code=settingsass="sre=lassXCOMM_CLOCK, current_speed) {
  56
  67 lass!OMM_CLOCK, t->tx_bufa href="+code=t"x_buf">cuts_per_word, t->rx_bufa href="+code=trx_buf">cuts_per_word && t->) {
  67 ="L53">  53        ""L7u="+code=settings""L7u=lassf">        return -EINVAL;
  69         breakpi/spi.h>
  80 ="L72">  72}
  81
  69  53        ""L7u="+code=settings""L7u=lassf"> 53        "a href="+code=spi_xcomm_setup_transfer" class="sref">spi_xcomm_setuspi_xcomm *speed_hz : , , &  69  66        if (<"L7u="+code=settings""L7u=lassff">le0sref">BIT(6)
  67         breakpi/spi.h>
  65
  8685" c_xcomm-> 53        list_, &t->tts="sre_list"+code=settingsass="sre_list">cusshipselect, &ascomm_sync_configasclassss="sref">t->ass="sre="+code=settingsass="sre=lassfpi/spi.h>
  67                lect, &t->>
  78
  69  66        if (->BIT(6)
  80  69  53        "a href="+code=settings" class="sre>chipselect |=   69  68        else
  69  69  53        "a href="+code=settings" class="sre>chipselect &= ~  73
  67  79 ? t->rx_bufa href="+code=trx_buf">current_speed) {
  85 ="L66"> settings = spi_xcomm-> 53        "a href="+code=settings" class="sref">settings;
  8685" c="L66"> settings = <"L7u="+code=settings""L7u=lassf"> 53        "a href="+code=spi_xcomm_sync_config" class="sref">spi_xcomm_sspi_xcomm *speed_hz : t->>
  67          66        if (<"L7u="+code=settings""L7u=lassff">le0sref">BIT(6)
  67 ="L53">         breakpi/spi.h>
  69 }c 68speed != spi_xcomm->"a href="+code=settings" class="sre>cord != 8) || ) {
  80 ="L66"> settings = spi_xcomm-> 53        "a href="+code=settings" class="sref">settings;
  69         settings = <"L7u="+code=settings""L7u=lassf"> 53        "a href="+code=spi_xcomm_sync_config" class="sref">spi_xcomm_sspi_xcomm *0=x/init.h>
  69  69  66        if (<"L7u="+code=settings""L7u=lassff">le0sref">BIT(6)
  69                 breakpi/spi.h>
  67 ="L72">  72}
  65
  8685" class="line" namif (t->) {
  67         settings = <"L7u="+code=settings""L7u=lassf"> 53        "a href="+txrx_buf="+code=settings"a href="+txrx_buf=_setuspi_xcomm *speed_hz : , >
  78
  69          66        if (<"L7u="+code=settings""L7u=lassff">le0sref">BIT(6)
  80                 breakpi/spi.h>
  81
  69  69  66        if (<"L7u="+code=settings""L7u=lassffg>le0sref">BIT(6)
  69  67         settings = ascomm_sync_configasclassss="sref">t->actual_" cgthomm_sync_configactual_" cgthname=+"> 53        ""L7u="+code=settings""L7u=lasspi/spi.h>
  67 ="L72">  72}
  85 static int <"L7u="+code=settings""L7u=lassf">0sref">speed;
  56
  67 lass="line" namif (t->delay_useBIT(6)
  67 ="L53">  53        udelay href="+code=csudelaycomm_spi_xcomm *t->delay_usespeed;
  59
  80 ">speed != settings = fa68>
 ="L72">  72}
  52
  66        if (<"L7u="+code=settings""L7u=lassfref0>cor!OMM_CLOCK, BIT(6)
  67  53        "a href="+code=spi_xcomm_chipselect" class="sref">spi_xcomm_spi_xcomm *speed_hz : , fa68speed;
  65
 settings = ascomm_sync_configasclassss="sref">t-><"L7u="+code=settings""L7u=lassf"> 53        ""L7u="+code=settings""L7u=lasspi/spi.h>
  47        " clfiss="ze_" class=aessag *ass="sprcode=settingsass="sf">s=x/init.h>
  78
        static int ""L7u="+code=settings""L7u=lasspi/spi.h>
  72}
  81
  74static int comm_p_transfer(struct spi_device *BIT(6)
  84        if (spi->bits_pernt_speed) {
  85                return -EINVAL;
  56
  570sref">speed;
  58}
  59
  74static int _lass=nixcomm_chipselect_lass=nixname=static int spi_device *  59
 const p_transfer(struct " class="s_i=i2c_master_send" class="s_i=ref">spi_device *<=i2c_master_send"dlasssref">BIT(6)
  62{
 p_transfer(struct spi_xcomm *speed;
 p_transfer(struct spi_transfer *ass="sprcode=settingsass="sf">ssref">speed;
   74static int respeed;
  56
  47        ass="sprcode=settingsass="sf">sf"> 53        "a hallochass="sprcode=settings"a hallochass="scomm_hipselect, &t->devi2c_master_senddevlassXCs"zeof(>spi_xcomm * lass!OMM_CLOCK, ass="sprcode=settingsass="sf">s=/init.h>
  69                return -speed;
  65
  71        s=x/init.h>
  82        spi_xcomm->buf[0] = >
  73
 aster_send(ass="sprcode=settingsass="sf">s">spi_xcomm->nu"+code=spi_xcomm_chipselectnu"+code=spi_xlassref16x/init.h>
  55        ass="sprcode=settingsass="sf">s">spi_xcomm->">_" clprcode=settingsa>_" cllassref">buf[0] =  != 8) ||  != 8) || >
 settings = ass="sprcode=settingsass="sf">s">spi_xcomm->flaf="+code=settingsflaf=lassref">buf[0] = >
  47        ass="sprcode=settingsass="sf">s">spi_xcomm->commf"> 53        "a href="+code=_setup_transfer" class="sref">commx/init.h>
  47        ass="sprcode=settingsass="sf">s">spi_xcomm->tss="sre_"><=aessag<=aessag 53        "a href="+tss="sre_"><_setx/init.h>
  47        ass="sprcode=settingsass="sf">s">spi_xcomm->devi2c_master_senddevlass._xcomm->of_nogtde=max_speed_hzof_nogtlassref">buf[0] = spi_xcomm->devi2c_master_senddevlass._xcomm->of_nogtde=max_speed_hzof_nogtlassx/init.h>
 fer(struct " clreflcliassdataprcode=settings" clreflcliassdatai2c_master_send(i2c, ass="sprcode=settingsass="sf">s=x/init.h>
  81
  82        rebuf[0] = "a hregis="srass="sprcode=settings"a hregis="srass="si2c_master_send(ass="sprcode=settingsass="sf">s=x/init.h>
  66        if (rele0sref">BIT(6)
  67  53        "a hass="srpuxcomm_chipselect" class="srpuxi2c_master_send(ass="sprcode=settingsass="sf">s=x/init.h>
  65
        static int respeed;
  72}
  78
  74static int _lassexixcomm_chipselect_lassexixname=static int spi_device *BIT(6)
  62{
 p_transfer(struct spi_transfer *ass="sprcode=settingsass="sf">sref">buf[0] = (>
  52
  53        "a hunregis="srass="sprcode=settings"a hunregis="srass="si2c_master_send(ass="sprcode=settingsass="sf">s=x/init.h>
  44
  570sref">speed;
  72}
  72}
const p_transfer(struct " class="s_i=i2c_master_send" class="s_i=ref">static int   62{
 { "f="driver" }=="L59">  59
 { }=="L59">  59
speed;
  52
p_transfer(struct " cla
i2c_master_send" cla
ref">static int 
f">sref="L62">  62{
 ._xcomm->a
i2c_master_senda
f">sref="L62">  62{
  85 ._xcomm->" clcomm_chipselectn clname="L= "f="driver"=="L59">  59
  8685" c._xcomm->own>
i2c_master_sendown>
name="ef">buf[0] = THIS_MODULM_SETTINGS_3WIRETHIS_MODULMlass=="L59">  59
 }=="L59">  59
 ._xcomm->id_tabllcomm_chipselectid_tabllname="L67">"> 53        "a href="+id="+code=settings"a href="+id=ref"=="L59">  59
 ._xcomm->prob  8685" c"> 53        "a href="+prob  59
 ._xcomm->remov 53        _lassexix_=_setup_transfer_lassexix_=i2c_master_send(  59
speed;

i2c_master_send"&guls_i cla
i2c_master_send(
f">s=x/init.h>
  73
"GPL"=x/init.h>
"Lars-Pe="s Clausenrf">llars@metafoo.de>spi"=x/init.h>
"Analog Dss="ss AD-FMss="S1-EBZ board I2C-SPI bridge >>
"=x/init.h>
lxs@d="ux.nolass.
Redpill L="pro ASlass="provid"s of L="ux>consullass and operL74ons sers="ss sincen19 5.