Add lan9252 for Linux (#28)

- Add kernel device driver
     drivers/linux/lan9252
 - Add lan9252 file for linux
     applications/linux_lan9252demo
     soes/hal/linux-lan9252
 - Fix linux compatibility for cc.h
     #ifdef __linux__
pull/22/merge
DonBit 2017-10-15 22:50:50 +09:00 committed by nakarlsson
parent deb4d3743f
commit eda5a1dc76
15 changed files with 2454 additions and 1 deletions

View File

@ -0,0 +1,35 @@
#ifndef __CONFIG_H__
#define __CONFIG_H__
#include <cc.h>
#define MBXSIZE 128
#define MBXSIZEBOOT 128
#define MBXBUFFERS 3
#define MBX0_sma 0x1000
#define MBX0_sml MBXSIZE
#define MBX0_sme MBX0_sma+MBX0_sml-1
#define MBX0_smc 0x26
#define MBX1_sma MBX0_sma+MBX0_sml
#define MBX1_sml MBXSIZE
#define MBX1_sme MBX1_sma+MBX1_sml-1
#define MBX1_smc 0x22
#define MBX0_sma_b 0x1000
#define MBX0_sml_b MBXSIZEBOOT
#define MBX0_sme_b MBX0_sma_b+MBX0_sml_b-1
#define MBX0_smc_b 0x26
#define MBX1_sma_b MBX0_sma_b+MBX0_sml_b
#define MBX1_sml_b MBXSIZEBOOT
#define MBX1_sme_b MBX1_sma_b+MBX1_sml_b-1
#define MBX1_smc_b 0x22
#define SM2_sma 0x1100
#define SM2_smc 0x24
#define SM2_act 1
#define SM3_sma 0x1180
#define SM3_smc 0x20
#define SM3_act 1
#endif /* __CONFIG_H__ */

View File

@ -0,0 +1,47 @@
#include <stdio.h>
/**
* This function reads physical input values and assigns the corresponding members
* of Rb.Buttons
*/
void cb_get_Buttons()
{
}
/**
* This function writes physical output values from the corresponding members of
* Wb.LEDs
*/
void cb_set_LEDs()
{
}
/**
* This function is called after a SDO write of the object Cb.Parameters.
*/
void cb_post_write_Parameters(int subindex)
{
}
void main_run(void * arg)
{
soes_init();
while(1) {
soes();
}
}
int main(void)
{
printf("Hello Main\n");
main_run(NULL);
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,265 @@
#include <stddef.h>
#include "utypes.h"
#include "soes/esc.h"
#include "soes/esc_coe.h"
#include "soes/esc_foe.h"
#include "slave.h"
#ifndef EEP_EMULATION
#define EEP_EMULATION 0 /* Set to 1 for EEPROM emulation */
#endif
#define WATCHDOG_RESET_VALUE 150
#define DEFAULTTXPDOMAP 0x1a00
#define DEFAULTRXPDOMAP 0x1600
#define DEFAULTTXPDOITEMS 1
#define DEFAULTRXPDOITEMS 1
volatile _ESCvar ESCvar;
_MBX MBX[MBXBUFFERS];
_MBXcontrol MBXcontrol[MBXBUFFERS];
uint8_t MBXrun=0;
uint16_t SM2_sml,SM3_sml;
_Rbuffer Rb;
_Wbuffer Wb;
_Cbuffer Cb;
_App App;
uint16_t TXPDOsize,RXPDOsize;
uint16_t txpdomap = DEFAULTTXPDOMAP;
uint16_t rxpdomap = DEFAULTRXPDOMAP;
uint8_t txpdoitems = DEFAULTTXPDOITEMS;
uint8_t rxpdoitems = DEFAULTTXPDOITEMS;
static unsigned int watchdog = WATCHDOG_RESET_VALUE;
static void (*application_loop_callback)(void) = NULL;
/** Mandatory: Hook called from the slave stack SDO Download handler to act on
* user specified Index and Sub-index.
*
* @param[in] index = index of SDO download request to handle
* @param[in] sub-index = sub-index of SDO download request to handle
*/
void ESC_objecthandler (uint16_t index, uint8_t subindex)
{
switch (index)
{
case 0x1c12:
{
if (rxpdoitems > 1)
{
rxpdoitems = 1;
}
if ((rxpdomap != 0x1600) && (rxpdomap != 0x1601)
&& (rxpdomap != 0x0000))
{
rxpdomap = 0x1600;
}
RXPDOsize = SM2_sml = sizeRXPDO();
break;
}
case 0x1c13:
{
if (txpdoitems > 1)
{
txpdoitems = 1;
}
if ((txpdomap != 0x1A00) && (txpdomap != 0x1A01)
&& (rxpdomap != 0x0000))
{
txpdomap = 0x1A00;
}
TXPDOsize = SM3_sml = sizeTXPDO();
break;
}
/* Handle post-write of parameter values */
case 0x8000:
{
cb_post_write_Parameters(subindex);
break;
}
default:
break;
}
}
/** Mandatory: Hook called from the slave stack ESC_stopoutputs to act on state changes
* forcing us to stop outputs. Here we can set them to a safe state.
* set
*/
void APP_safeoutput (void)
{
DPRINT ("APP_safeoutput\n");
// Set safe values for Wb.LEDs
Wb.LEDs.LED0 = 0;
Wb.LEDs.LED1 = 0;
}
/** Mandatory: Write local process data to Sync Manager 3, Master Inputs.
*/
void TXPDO_update (void)
{
ESC_write (SM3_sma, &Rb, TXPDOsize);
}
/** Mandatory: Read Sync Manager 2 to local process data, Master Outputs.
*/
void RXPDO_update (void)
{
ESC_read (SM2_sma, &Wb, RXPDOsize);
}
/** Mandatory: Function to update local I/O, call read ethercat outputs, call
* write ethercat inputs. Implement watch-dog counter to count-out if we have
* made state change affecting the App.state.
*/
void DIG_process (void)
{
if (watchdog > 0)
{
watchdog--;
}
if (App.state & APPSTATE_OUTPUT)
{
/* SM2 trigger ? */
if (ESCvar.ALevent & ESCREG_ALEVENT_SM2)
{
ESCvar.ALevent &= ~ESCREG_ALEVENT_SM2;
RXPDO_update();
watchdog = WATCHDOG_RESET_VALUE;
/* Set outputs */
cb_set_LEDs();
}
if (watchdog == 0)
{
DPRINT("DIG_process watchdog expired\n");
ESC_stopoutput();
/* watchdog, invalid outputs */
ESC_ALerror (ALERR_WATCHDOG);
/* goto safe-op with error bit set */
ESC_ALstatus (ESCsafeop | ESCerror);
}
}
else
{
watchdog = WATCHDOG_RESET_VALUE;
}
if (App.state)
{
/* Update inputs */
cb_get_Buttons();
TXPDO_update();
}
}
/********** TODO: Generic code beyond this point ***************/
static const char *spi_name = "/dev/lan9252";
/** Optional: Hook called after state change for application specific
* actions for specific state changes.
*/
void post_state_change_hook (uint8_t * as, uint8_t * an)
{
#if 0
/* Add specific step change hooks here */
if ((*as == BOOT_TO_INIT) && (*an == ESCinit))
{
boot_inithook();
}
else if((*as == INIT_TO_BOOT) && (*an & ESCerror ) == 0)
{
init_boothook();
}
#endif
}
/**
* Set callback run once every loop in the SOES application loop.
*/
void set_application_loop_hook(void (*callback)(void))
{
application_loop_callback = callback;
}
/**
* SOES main function. It should be called periodically.
* Reads the EtherCAT state and status. Responsible for I/O updates.
*/
void soes (void)
{
/* On init restore PDO mappings to default size */
if((ESCvar.ALstatus & 0x0f) == ESCinit)
{
txpdomap = DEFAULTTXPDOMAP;
rxpdomap = DEFAULTRXPDOMAP;
txpdoitems = DEFAULTTXPDOITEMS;
rxpdoitems = DEFAULTTXPDOITEMS;
}
/* Read local time from ESC */
ESC_read (ESCREG_LOCALTIME, (void *) &ESCvar.Time, sizeof (ESCvar.Time));
ESCvar.Time = etohl (ESCvar.Time);
/* Check the state machine */
ESC_state();
/* Check mailboxes */
if (ESC_mbxprocess())
{
ESC_coeprocess();
ESC_foeprocess();
ESC_xoeprocess();
}
DIG_process();
#if EEP_EMULATION
EEP_process ();
EEP_hw_process();
#endif /* EEP_EMULATION */
if (application_loop_callback != NULL)
{
(application_loop_callback)();
}
}
/**
* Initialize the SOES stack.
*/
void soes_init (void)
{
DPRINT ("SOES (Simple Open EtherCAT Slave)\n");
TXPDOsize = SM3_sml = sizeTXPDO();
RXPDOsize = SM2_sml = sizeRXPDO();
/* Setup post config hooks */
static esc_cfg_t config =
{
.pre_state_change_hook = NULL,
.post_state_change_hook = post_state_change_hook
};
ESC_config ((esc_cfg_t *)&config);
ESC_reset();
ESC_init ((void *)spi_name);
/* wait until ESC is started up */
while ((ESCvar.DLstatus & 0x0001) == 0)
{
ESC_read (ESCREG_DLSTATUS, (void *) &ESCvar.DLstatus,
sizeof (ESCvar.DLstatus));
ESCvar.DLstatus = etohs (ESCvar.DLstatus);
}
/* Init FoE */
FOE_init();
/* reset ESC to init state */
ESC_ALstatus (ESCinit);
ESC_ALerror (ALERR_NONE);
ESC_stopmbx();
ESC_stopinput();
ESC_stopoutput();
}

View File

@ -0,0 +1,298 @@
<?xml version="1.0" encoding="UTF-8"?>
<Slave id="evb9252_dig" productCode="1234">
<Name>lan9252</Name>
<Vendor>
<Id>0x1337</Id>
<Name>rt-labs AB</Name>
</Vendor>
<Group>
<Type>lan9252_spi</Type>
<Name>lan9252</Name>
</Group>
<Fmmu>Outputs</Fmmu>
<Fmmu>Inputs</Fmmu>
<Sm ControlByte="0x26" DefaultSize="128" StartAddress="0x1000">MBoxOut</Sm>
<Sm ControlByte="0x22" DefaultSize="128" StartAddress="0x1080">MBoxIn</Sm>
<Sm ControlByte="0x24" DefaultSize="0" StartAddress="0x1100">Outputs</Sm>
<Sm ControlByte="0x20" DefaultSize="0" StartAddress="0x1180">Inputs</Sm>
<Mailbox CoE="true" FoE="true">
<Bootstrap Length="128" Start="0x1000"/>
<Standard Length="128" Start="0x1000"/>
</Mailbox>
<Eeprom>
<ConfigData>8002000000000000</ConfigData>
<BootStrap>0010800080108000</BootStrap>
</Eeprom>
<Dictionary>
<Item>
<Name>Device Type</Name>
<Index>0x1000</Index>
<DataType>UNSIGNED32</DataType>
<DefaultValue>0x01901389</DefaultValue>
</Item>
<Item Managed="true">
<Name>Device Name</Name>
<Index>0x1008</Index>
<DataType>VISIBLE_STRING</DataType>
<DefaultValue>evb9252_dig</DefaultValue>
</Item>
<Item>
<Name>Hardware Version</Name>
<Index>0x1009</Index>
<DataType>VISIBLE_STRING</DataType>
<DefaultValue>1.0</DefaultValue>
</Item>
<Item>
<Name>Software Version</Name>
<Index>0x100A</Index>
<DataType>VISIBLE_STRING</DataType>
<DefaultValue>1.0</DefaultValue>
</Item>
<Item Managed="true">
<Name>Identity Object</Name>
<Index>0x1018</Index>
<DataType>RECORD</DataType>
<SubItem>
<Name>Number of Elements</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>4</DefaultValue>
</SubItem>
<SubItem>
<Name>Vendor ID</Name>
<DataType>UNSIGNED32</DataType>
<DefaultValue>0x1337</DefaultValue>
</SubItem>
<SubItem>
<Name>Product Code</Name>
<DataType>UNSIGNED32</DataType>
<DefaultValue>1234</DefaultValue>
</SubItem>
<SubItem>
<Name>Revision Number</Name>
<DataType>UNSIGNED32</DataType>
<DefaultValue>0</DefaultValue>
</SubItem>
<SubItem>
<Name>Serial Number</Name>
<DataType>UNSIGNED32</DataType>
<DefaultValue>0x00000000</DefaultValue>
</SubItem>
</Item>
<Item Managed="true">
<Name>LEDs</Name>
<Index>0x1600</Index>
<DataType>RECORD</DataType>
<SubItem>
<Name>Number of Elements</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>2</DefaultValue>
</SubItem>
<SubItem>
<Name>LED0</Name>
<DataType>UNSIGNED32</DataType>
<DefaultValue>0x70000108</DefaultValue>
</SubItem>
<SubItem>
<Name>LED1</Name>
<DataType>UNSIGNED32</DataType>
<DefaultValue>0x70000208</DefaultValue>
</SubItem>
</Item>
<Item Managed="true">
<Name>Buttons</Name>
<Index>0x1A00</Index>
<DataType>RECORD</DataType>
<SubItem>
<Name>Number of Elements</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>1</DefaultValue>
</SubItem>
<SubItem>
<Name>Button1</Name>
<DataType>UNSIGNED32</DataType>
<DefaultValue>0x60000108</DefaultValue>
</SubItem>
</Item>
<Item Managed="true">
<Name>Sync Manager Communication Type</Name>
<Index>0x1C00</Index>
<DataType>ARRAY</DataType>
<SubItem>
<Name>Number of Elements</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>4</DefaultValue>
</SubItem>
<SubItem>
<Name>Communications Type SM0</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>1</DefaultValue>
</SubItem>
<SubItem>
<Name>Communications Type SM1</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>2</DefaultValue>
</SubItem>
<SubItem>
<Name>Communications Type SM2</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>3</DefaultValue>
</SubItem>
<SubItem>
<Name>Communications Type SM3</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>4</DefaultValue>
</SubItem>
</Item>
<Item Managed="true">
<Name>Sync Manager 2 PDO Assignment</Name>
<Index>0x1C12</Index>
<DataType>ARRAY</DataType>
<SubItem>
<Name>Number of Elements</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>1</DefaultValue>
</SubItem>
<SubItem>
<Name>PDO Mapping</Name>
<DataType>UNSIGNED16</DataType>
<DefaultValue>0x1600</DefaultValue>
</SubItem>
</Item>
<Item Managed="true">
<Name>Sync Manager 3 PDO Assignment</Name>
<Index>0x1C13</Index>
<DataType>ARRAY</DataType>
<SubItem>
<Name>Number of Elements</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>1</DefaultValue>
</SubItem>
<SubItem>
<Name>PDO Mapping</Name>
<DataType>UNSIGNED16</DataType>
<DefaultValue>0x1A00</DefaultValue>
</SubItem>
</Item>
<Item Managed="true">
<Name>Buttons</Name>
<Index>0x6000</Index>
<DataType>RECORD</DataType>
<Variable>Buttons</Variable>
<VariableType>Input</VariableType>
<SubItem>
<Name>Number of Elements</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>1</DefaultValue>
</SubItem>
<SubItem>
<Name>Button1</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>0</DefaultValue>
<Access>RO</Access>
<Variable>Button1</Variable>
<VariableType>Input</VariableType>
</SubItem>
</Item>
<Item Managed="true">
<Name>LEDs</Name>
<Index>0x7000</Index>
<DataType>RECORD</DataType>
<Variable>LEDs</Variable>
<VariableType>Output</VariableType>
<SubItem>
<Name>Number of Elements</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>2</DefaultValue>
</SubItem>
<SubItem>
<Name>LED0</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>0</DefaultValue>
<Access>RO</Access>
<Variable>LED0</Variable>
<VariableType>Output</VariableType>
</SubItem>
<SubItem>
<Name>LED1</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>0</DefaultValue>
<Access>RO</Access>
<Variable>LED1</Variable>
<VariableType>Output</VariableType>
</SubItem>
</Item>
<Item Managed="true">
<Name>Parameters</Name>
<Index>0x8000</Index>
<DataType>RECORD</DataType>
<Variable>Parameters</Variable>
<VariableType>Parameter</VariableType>
<SubItem>
<Name>Number of Elements</Name>
<DataType>UNSIGNED8</DataType>
<DefaultValue>1</DefaultValue>
</SubItem>
<SubItem>
<Name>Multiplier</Name>
<DataType>UNSIGNED32</DataType>
<DefaultValue>0</DefaultValue>
<Access>RW</Access>
<Variable>Multiplier</Variable>
<VariableType>Parameter</VariableType>
</SubItem>
</Item>
</Dictionary>
<RxPdo>
<Index>0x1600</Index>
<Container>LEDs</Container>
<Name>LEDs</Name>
<Entry>
<Index>0x7000</Index>
<SubIndex>1</SubIndex>
<Variable>LED0</Variable>
</Entry>
<Entry>
<Index>0x7000</Index>
<SubIndex>2</SubIndex>
<Variable>LED1</Variable>
</Entry>
</RxPdo>
<TxPdo>
<Index>0x1A00</Index>
<Container>Buttons</Container>
<Name>Buttons</Name>
<Entry>
<Index>0x6000</Index>
<SubIndex>1</SubIndex>
<Variable>Button1</Variable>
</Entry>
</TxPdo>
<Input>
<Name>Buttons</Name>
<Type>RECORD</Type>
<Member>
<Name>Button1</Name>
<Type>UNSIGNED8</Type>
</Member>
</Input>
<Output>
<Name>LEDs</Name>
<Type>RECORD</Type>
<Member>
<Name>LED0</Name>
<Type>UNSIGNED8</Type>
</Member>
<Member>
<Name>LED1</Name>
<Type>UNSIGNED8</Type>
</Member>
</Output>
<Parameter>
<Name>Parameters</Name>
<Type>RECORD</Type>
<Member>
<Name>Multiplier</Name>
<Type>UNSIGNED32</Type>
</Member>
</Parameter>
</Slave>

View File

@ -0,0 +1,38 @@
#ifndef __SLAVE_H__
#define __SLAVE_H__
#include "utypes.h"
/**
* This function reads physical input values and assigns the corresponding members
* of Rb.Buttons
*/
void cb_get_Buttons();
/**
* This function writes physical output values from the corresponding members of
* Wb.LEDs
*/
void cb_set_LEDs();
/**
* This function is called after a SDO write of the object Cb.Parameters.
*/
void cb_post_write_Parameters(int subindex);
/**
* This function sets an application loop callback function.
*/
void set_application_loop_hook(void (*callback)(void));
/**
* Main function for SOES application
*/
void soes (void);
/**
* Initialize the SOES stack
*/
void soes_init (void);
#endif /* __SLAVE_H__ */

View File

@ -0,0 +1,691 @@
<?xml version="1.0" encoding="UTF-8"?>
<EtherCATInfo>
<Vendor>
<Id>#x1337</Id>
<Name LcId="1033">rt-labs AB</Name>
</Vendor>
<Descriptions>
<Groups>
<Group>
<Type>lan9252_spi</Type>
<Name LcId="1033">lan9252</Name>
</Group>
</Groups>
<Devices>
<Device Physics="YY">
<Type ProductCode="1234" RevisionNo="0">evb9252_dig</Type>
<Name LcId="1033">lan9252</Name>
<GroupType>lan9252_spi</GroupType>
<Profile>
<ProfileNo>5001</ProfileNo>
<AddInfo>400</AddInfo>
<Dictionary>
<DataTypes>
<DataType>
<Name>DT1018</Name>
<BitSize>144</BitSize>
<SubItem>
<SubIdx>0</SubIdx>
<Name>Number of Elements</Name>
<Type>USINT</Type>
<BitSize>8</BitSize>
<BitOffs>0</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<SubIdx>1</SubIdx>
<Name>Vendor ID</Name>
<Type>UDINT</Type>
<BitSize>32</BitSize>
<BitOffs>16</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<SubIdx>2</SubIdx>
<Name>Product Code</Name>
<Type>UDINT</Type>
<BitSize>32</BitSize>
<BitOffs>48</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<SubIdx>3</SubIdx>
<Name>Revision Number</Name>
<Type>UDINT</Type>
<BitSize>32</BitSize>
<BitOffs>80</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<SubIdx>4</SubIdx>
<Name>Serial Number</Name>
<Type>UDINT</Type>
<BitSize>32</BitSize>
<BitOffs>112</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
</DataType>
<DataType>
<Name>DT1600</Name>
<BitSize>80</BitSize>
<SubItem>
<SubIdx>0</SubIdx>
<Name>Number of Elements</Name>
<Type>USINT</Type>
<BitSize>8</BitSize>
<BitOffs>0</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<SubIdx>1</SubIdx>
<Name>LED0</Name>
<Type>UDINT</Type>
<BitSize>32</BitSize>
<BitOffs>16</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<SubIdx>2</SubIdx>
<Name>LED1</Name>
<Type>UDINT</Type>
<BitSize>32</BitSize>
<BitOffs>48</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
</DataType>
<DataType>
<Name>DT1A00</Name>
<BitSize>48</BitSize>
<SubItem>
<SubIdx>0</SubIdx>
<Name>Number of Elements</Name>
<Type>USINT</Type>
<BitSize>8</BitSize>
<BitOffs>0</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<SubIdx>1</SubIdx>
<Name>Button1</Name>
<Type>UDINT</Type>
<BitSize>32</BitSize>
<BitOffs>16</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
</DataType>
<DataType>
<Name>DT1C00ARR</Name>
<BaseType>USINT</BaseType>
<BitSize>32</BitSize>
<ArrayInfo>
<LBound>1</LBound>
<Elements>4</Elements>
</ArrayInfo>
</DataType>
<DataType>
<Name>DT1C00</Name>
<BitSize>48</BitSize>
<SubItem>
<SubIdx>0</SubIdx>
<Name>Number of Elements</Name>
<Type>USINT</Type>
<BitSize>8</BitSize>
<BitOffs>0</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<Name>Elements</Name>
<Type>DT1C00ARR</Type>
<BitSize>32</BitSize>
<BitOffs>16</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
</DataType>
<DataType>
<Name>DT1C12ARR</Name>
<BaseType>UINT</BaseType>
<BitSize>16</BitSize>
<ArrayInfo>
<LBound>1</LBound>
<Elements>1</Elements>
</ArrayInfo>
</DataType>
<DataType>
<Name>DT1C12</Name>
<BitSize>32</BitSize>
<SubItem>
<SubIdx>0</SubIdx>
<Name>Number of Elements</Name>
<Type>USINT</Type>
<BitSize>8</BitSize>
<BitOffs>0</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<Name>Elements</Name>
<Type>DT1C12ARR</Type>
<BitSize>16</BitSize>
<BitOffs>16</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
</DataType>
<DataType>
<Name>DT1C13ARR</Name>
<BaseType>UINT</BaseType>
<BitSize>16</BitSize>
<ArrayInfo>
<LBound>1</LBound>
<Elements>1</Elements>
</ArrayInfo>
</DataType>
<DataType>
<Name>DT1C13</Name>
<BitSize>32</BitSize>
<SubItem>
<SubIdx>0</SubIdx>
<Name>Number of Elements</Name>
<Type>USINT</Type>
<BitSize>8</BitSize>
<BitOffs>0</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<Name>Elements</Name>
<Type>DT1C13ARR</Type>
<BitSize>16</BitSize>
<BitOffs>16</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
</DataType>
<DataType>
<Name>DT6000</Name>
<BitSize>24</BitSize>
<SubItem>
<SubIdx>0</SubIdx>
<Name>Number of Elements</Name>
<Type>USINT</Type>
<BitSize>8</BitSize>
<BitOffs>0</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<SubIdx>1</SubIdx>
<Name>Button1</Name>
<Type>USINT</Type>
<BitSize>8</BitSize>
<BitOffs>16</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
</DataType>
<DataType>
<Name>DT7000</Name>
<BitSize>32</BitSize>
<SubItem>
<SubIdx>0</SubIdx>
<Name>Number of Elements</Name>
<Type>USINT</Type>
<BitSize>8</BitSize>
<BitOffs>0</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<SubIdx>1</SubIdx>
<Name>LED0</Name>
<Type>USINT</Type>
<BitSize>8</BitSize>
<BitOffs>16</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<SubIdx>2</SubIdx>
<Name>LED1</Name>
<Type>USINT</Type>
<BitSize>8</BitSize>
<BitOffs>24</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
</DataType>
<DataType>
<Name>DT8000</Name>
<BitSize>48</BitSize>
<SubItem>
<SubIdx>0</SubIdx>
<Name>Number of Elements</Name>
<Type>USINT</Type>
<BitSize>8</BitSize>
<BitOffs>0</BitOffs>
<Flags>
<Access>ro</Access>
</Flags>
</SubItem>
<SubItem>
<SubIdx>1</SubIdx>
<Name>Multiplier</Name>
<Type>UDINT</Type>
<BitSize>32</BitSize>
<BitOffs>16</BitOffs>
<Flags>
<Access>rw</Access>
</Flags>
</SubItem>
</DataType>
<DataType>
<Name>STRING(3)</Name>
<BitSize>24</BitSize>
</DataType>
<DataType>
<Name>STRING(11)</Name>
<BitSize>88</BitSize>
</DataType>
<DataType>
<Name>UDINT</Name>
<BitSize>32</BitSize>
</DataType>
<DataType>
<Name>UINT</Name>
<BitSize>16</BitSize>
</DataType>
<DataType>
<Name>USINT</Name>
<BitSize>8</BitSize>
</DataType>
</DataTypes>
<Objects>
<Object>
<Index>#x1000</Index>
<Name>Device Type</Name>
<Type>UDINT</Type>
<BitSize>32</BitSize>
<Info>
<DefaultValue>#x01901389</DefaultValue>
</Info>
<Flags>
<Access>ro</Access>
<Category>m</Category>
</Flags>
</Object>
<Object>
<Index>#x1008</Index>
<Name>Device Name</Name>
<Type>STRING(11)</Type>
<BitSize>88</BitSize>
<Info>
<DefaultString>evb9252_dig</DefaultString>
</Info>
<Flags>
<Access>ro</Access>
</Flags>
</Object>
<Object>
<Index>#x1009</Index>
<Name>Hardware Version</Name>
<Type>STRING(3)</Type>
<BitSize>24</BitSize>
<Info>
<DefaultString>1.0</DefaultString>
</Info>
<Flags>
<Access>ro</Access>
<Category>o</Category>
</Flags>
</Object>
<Object>
<Index>#x100A</Index>
<Name>Software Version</Name>
<Type>STRING(3)</Type>
<BitSize>24</BitSize>
<Info>
<DefaultString>1.0</DefaultString>
</Info>
<Flags>
<Access>ro</Access>
</Flags>
</Object>
<Object>
<Index>#x1018</Index>
<Name>Identity Object</Name>
<Type>DT1018</Type>
<BitSize>144</BitSize>
<Info>
<SubItem>
<Name>Number of Elements</Name>
<Info>
<DefaultValue>4</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>Vendor ID</Name>
<Info>
<DefaultValue>#x1337</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>Product Code</Name>
<Info>
<DefaultValue>1234</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>Revision Number</Name>
<Info>
<DefaultValue>0</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>Serial Number</Name>
<Info>
<DefaultValue>#x00000000</DefaultValue>
</Info>
</SubItem>
</Info>
<Flags>
<Access>ro</Access>
</Flags>
</Object>
<Object>
<Index>#x1600</Index>
<Name>LEDs</Name>
<Type>DT1600</Type>
<BitSize>80</BitSize>
<Info>
<SubItem>
<Name>Number of Elements</Name>
<Info>
<DefaultValue>2</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>LED0</Name>
<Info>
<DefaultValue>#x70000108</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>LED1</Name>
<Info>
<DefaultValue>#x70000208</DefaultValue>
</Info>
</SubItem>
</Info>
<Flags>
<Access>ro</Access>
</Flags>
</Object>
<Object>
<Index>#x1A00</Index>
<Name>Buttons</Name>
<Type>DT1A00</Type>
<BitSize>48</BitSize>
<Info>
<SubItem>
<Name>Number of Elements</Name>
<Info>
<DefaultValue>1</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>Button1</Name>
<Info>
<DefaultValue>#x60000108</DefaultValue>
</Info>
</SubItem>
</Info>
<Flags>
<Access>ro</Access>
</Flags>
</Object>
<Object>
<Index>#x1C00</Index>
<Name>Sync Manager Communication Type</Name>
<Type>DT1C00</Type>
<BitSize>48</BitSize>
<Info>
<SubItem>
<Name>Number of Elements</Name>
<Info>
<DefaultValue>4</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>Communications Type SM0</Name>
<Info>
<DefaultValue>1</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>Communications Type SM1</Name>
<Info>
<DefaultValue>2</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>Communications Type SM2</Name>
<Info>
<DefaultValue>3</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>Communications Type SM3</Name>
<Info>
<DefaultValue>4</DefaultValue>
</Info>
</SubItem>
</Info>
<Flags>
<Access>ro</Access>
</Flags>
</Object>
<Object>
<Index>#x1C12</Index>
<Name>Sync Manager 2 PDO Assignment</Name>
<Type>DT1C12</Type>
<BitSize>32</BitSize>
<Info>
<SubItem>
<Name>Number of Elements</Name>
<Info>
<DefaultValue>1</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>PDO Mapping</Name>
<Info>
<DefaultValue>#x1600</DefaultValue>
</Info>
</SubItem>
</Info>
<Flags>
<Access>ro</Access>
</Flags>
</Object>
<Object>
<Index>#x1C13</Index>
<Name>Sync Manager 3 PDO Assignment</Name>
<Type>DT1C13</Type>
<BitSize>32</BitSize>
<Info>
<SubItem>
<Name>Number of Elements</Name>
<Info>
<DefaultValue>1</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>PDO Mapping</Name>
<Info>
<DefaultValue>#x1A00</DefaultValue>
</Info>
</SubItem>
</Info>
<Flags>
<Access>ro</Access>
</Flags>
</Object>
<Object>
<Index>#x6000</Index>
<Name>Buttons</Name>
<Type>DT6000</Type>
<BitSize>24</BitSize>
<Info>
<SubItem>
<Name>Number of Elements</Name>
<Info>
<DefaultValue>1</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>Button1</Name>
<Info>
<DefaultValue>0</DefaultValue>
</Info>
</SubItem>
</Info>
<Flags>
<Access>ro</Access>
</Flags>
</Object>
<Object>
<Index>#x7000</Index>
<Name>LEDs</Name>
<Type>DT7000</Type>
<BitSize>32</BitSize>
<Info>
<SubItem>
<Name>Number of Elements</Name>
<Info>
<DefaultValue>2</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>LED0</Name>
<Info>
<DefaultValue>0</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>LED1</Name>
<Info>
<DefaultValue>0</DefaultValue>
</Info>
</SubItem>
</Info>
<Flags>
<Access>ro</Access>
</Flags>
</Object>
<Object>
<Index>#x8000</Index>
<Name>Parameters</Name>
<Type>DT8000</Type>
<BitSize>48</BitSize>
<Info>
<SubItem>
<Name>Number of Elements</Name>
<Info>
<DefaultValue>1</DefaultValue>
</Info>
</SubItem>
<SubItem>
<Name>Multiplier</Name>
<Info>
<DefaultValue>0</DefaultValue>
</Info>
</SubItem>
</Info>
<Flags>
<Access>ro</Access>
</Flags>
</Object>
</Objects>
</Dictionary>
</Profile>
<Fmmu>Outputs</Fmmu>
<Fmmu>Inputs</Fmmu>
<Sm ControlByte="#x26" DefaultSize="128" Enable="1" StartAddress="#x1000">MBoxOut</Sm>
<Sm ControlByte="#x22" DefaultSize="128" Enable="1" StartAddress="#x1080">MBoxIn</Sm>
<Sm ControlByte="#x24" Enable="1" StartAddress="#x1100">Outputs</Sm>
<Sm ControlByte="#x20" Enable="1" StartAddress="#x1180">Inputs</Sm>
<RxPdo Fixed="true" Mandatory="true" Sm="2">
<Index>#x1600</Index>
<Name>LEDs</Name>
<Entry>
<Index>#x7000</Index>
<SubIndex>1</SubIndex>
<BitLen>8</BitLen>
<Name>LED0</Name>
<DataType>USINT</DataType>
</Entry>
<Entry>
<Index>#x7000</Index>
<SubIndex>2</SubIndex>
<BitLen>8</BitLen>
<Name>LED1</Name>
<DataType>USINT</DataType>
</Entry>
</RxPdo>
<TxPdo Fixed="true" Mandatory="true" Sm="3">
<Index>#x1A00</Index>
<Name>Buttons</Name>
<Entry>
<Index>#x6000</Index>
<SubIndex>1</SubIndex>
<BitLen>8</BitLen>
<Name>Button1</Name>
<DataType>USINT</DataType>
</Entry>
</TxPdo>
<Mailbox DataLinkLayer="true">
<CoE CompleteAccess="false" PdoUpload="true" SdoInfo="true"/>
<FoE/>
</Mailbox>
<Eeprom>
<ByteSize>256</ByteSize>
<ConfigData>8002000000000000</ConfigData>
<BootStrap>0010800080108000</BootStrap>
</Eeprom>
</Device>
</Devices>
</Descriptions>
</EtherCATInfo>

View File

@ -0,0 +1,135 @@
#include "soes/esc_coe.h"
#include "utypes.h"
#include <stddef.h>
static const char acName1000[] = "Device Type";
static const char acName1000_0[] = "Device Type";
static const char acName1008[] = "Device Name";
static const char acName1008_0[] = "Device Name";
static const char acName1009[] = "Hardware Version";
static const char acName1009_0[] = "Hardware Version";
static const char acName100A[] = "Software Version";
static const char acName100A_0[] = "Software Version";
static const char acName1018[] = "Identity Object";
static const char acName1018_00[] = "Number of Elements";
static const char acName1018_01[] = "Vendor ID";
static const char acName1018_02[] = "Product Code";
static const char acName1018_03[] = "Revision Number";
static const char acName1018_04[] = "Serial Number";
static const char acName1600[] = "LEDs";
static const char acName1600_00[] = "Number of Elements";
static const char acName1600_01[] = "LED0";
static const char acName1600_02[] = "LED1";
static const char acName1A00[] = "Buttons";
static const char acName1A00_00[] = "Number of Elements";
static const char acName1A00_01[] = "Button1";
static const char acName1C00[] = "Sync Manager Communication Type";
static const char acName1C00_00[] = "Number of Elements";
static const char acName1C00_01[] = "Communications Type SM0";
static const char acName1C00_02[] = "Communications Type SM1";
static const char acName1C00_03[] = "Communications Type SM2";
static const char acName1C00_04[] = "Communications Type SM3";
static const char acName1C12[] = "Sync Manager 2 PDO Assignment";
static const char acName1C12_00[] = "Number of Elements";
static const char acName1C12_01[] = "PDO Mapping";
static const char acName1C13[] = "Sync Manager 3 PDO Assignment";
static const char acName1C13_00[] = "Number of Elements";
static const char acName1C13_01[] = "PDO Mapping";
static const char acName6000[] = "Buttons";
static const char acName6000_00[] = "Number of Elements";
static const char acName6000_01[] = "Button1";
static const char acName7000[] = "LEDs";
static const char acName7000_00[] = "Number of Elements";
static const char acName7000_01[] = "LED0";
static const char acName7000_02[] = "LED1";
static const char acName8000[] = "Parameters";
static const char acName8000_00[] = "Number of Elements";
static const char acName8000_01[] = "Multiplier";
const _objd SDO1000[] =
{
{0x0, DTYPE_UNSIGNED32, 32, ATYPE_RO, acName1000_0, 0x01901389, NULL},
};
const _objd SDO1008[] =
{
{0x0, DTYPE_VISIBLE_STRING, 88, ATYPE_RO, acName1008_0, 0, "evb9252_dig"},
};
const _objd SDO1009[] =
{
{0x0, DTYPE_VISIBLE_STRING, 24, ATYPE_RO, acName1009_0, 0, "1.0"},
};
const _objd SDO100A[] =
{
{0x0, DTYPE_VISIBLE_STRING, 24, ATYPE_RO, acName100A_0, 0, "1.0"},
};
const _objd SDO1018[] =
{
{0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName1018_00, 4, NULL},
{0x01, DTYPE_UNSIGNED32, 32, ATYPE_RO, acName1018_01, 0x1337, NULL},
{0x02, DTYPE_UNSIGNED32, 32, ATYPE_RO, acName1018_02, 1234, NULL},
{0x03, DTYPE_UNSIGNED32, 32, ATYPE_RO, acName1018_03, 0, NULL},
{0x04, DTYPE_UNSIGNED32, 32, ATYPE_RO, acName1018_04, 0x00000000, NULL},
};
const _objd SDO1600[] =
{
{0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName1600_00, 2, NULL},
{0x01, DTYPE_UNSIGNED32, 32, ATYPE_RO, acName1600_01, 0x70000108, NULL},
{0x02, DTYPE_UNSIGNED32, 32, ATYPE_RO, acName1600_02, 0x70000208, NULL},
};
const _objd SDO1A00[] =
{
{0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName1A00_00, 1, NULL},
{0x01, DTYPE_UNSIGNED32, 32, ATYPE_RO, acName1A00_01, 0x60000108, NULL},
};
const _objd SDO1C00[] =
{
{0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName1C00_00, 4, NULL},
{0x01, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName1C00_01, 1, NULL},
{0x02, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName1C00_02, 2, NULL},
{0x03, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName1C00_03, 3, NULL},
{0x04, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName1C00_04, 4, NULL},
};
const _objd SDO1C12[] =
{
{0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName1C12_00, 1, NULL},
{0x01, DTYPE_UNSIGNED16, 16, ATYPE_RO, acName1C12_01, 0x1600, NULL},
};
const _objd SDO1C13[] =
{
{0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName1C13_00, 1, NULL},
{0x01, DTYPE_UNSIGNED16, 16, ATYPE_RO, acName1C13_01, 0x1A00, NULL},
};
const _objd SDO6000[] =
{
{0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName6000_00, 1, NULL},
{0x01, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName6000_01, 0, &Rb.Buttons.Button1},
};
const _objd SDO7000[] =
{
{0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName7000_00, 2, NULL},
{0x01, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName7000_01, 0, &Wb.LEDs.LED0},
{0x02, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName7000_02, 0, &Wb.LEDs.LED1},
};
const _objd SDO8000[] =
{
{0x00, DTYPE_UNSIGNED8, 8, ATYPE_RO, acName8000_00, 1, NULL},
{0x01, DTYPE_UNSIGNED32, 32, ATYPE_RW, acName8000_01, 0, &Cb.Parameters.Multiplier},
};
const _objectlist SDOobjects[] =
{
{0x1000, OTYPE_VAR, 0, 0, acName1000, SDO1000},
{0x1008, OTYPE_VAR, 0, 0, acName1008, SDO1008},
{0x1009, OTYPE_VAR, 0, 0, acName1009, SDO1009},
{0x100A, OTYPE_VAR, 0, 0, acName100A, SDO100A},
{0x1018, OTYPE_RECORD, 4, 0, acName1018, SDO1018},
{0x1600, OTYPE_RECORD, 2, 0, acName1600, SDO1600},
{0x1A00, OTYPE_RECORD, 1, 0, acName1A00, SDO1A00},
{0x1C00, OTYPE_ARRAY, 4, 0, acName1C00, SDO1C00},
{0x1C12, OTYPE_ARRAY, 1, 0, acName1C12, SDO1C12},
{0x1C13, OTYPE_ARRAY, 1, 0, acName1C13, SDO1C13},
{0x6000, OTYPE_RECORD, 1, 0, acName6000, SDO6000},
{0x7000, OTYPE_RECORD, 2, 0, acName7000, SDO7000},
{0x8000, OTYPE_RECORD, 1, 0, acName8000, SDO8000},
{0xffff, 0xff, 0xff, 0xff, NULL, NULL}
};

View File

@ -0,0 +1,47 @@
#ifndef __UTYPES_H__
#define __UTYPES_H__
#include <cc.h>
CC_PACKED_BEGIN
typedef struct
{
CC_PACKED_BEGIN
struct
{
uint8_t Button1;
} CC_PACKED Buttons;
CC_PACKED_END
} CC_PACKED _Rbuffer;
CC_PACKED_END
CC_PACKED_BEGIN
typedef struct
{
CC_PACKED_BEGIN
struct
{
uint8_t LED0;
uint8_t LED1;
} CC_PACKED LEDs;
CC_PACKED_END
} CC_PACKED _Wbuffer;
CC_PACKED_END
CC_PACKED_BEGIN
typedef struct
{
CC_PACKED_BEGIN
struct
{
uint32_t Multiplier;
} CC_PACKED Parameters;
CC_PACKED_END
} CC_PACKED _Cbuffer;
CC_PACKED_END
extern _Rbuffer Rb;
extern _Wbuffer Wb;
extern _Cbuffer Cb;
#endif /* __UTYPES_H__ */

View File

@ -0,0 +1,4 @@
config LAN9252
tristate "Microchip LAN9252(ethercat slave controller) support"
help
SPI driver for Microchip LAN9252 ethercat slave controller interface.

View File

@ -0,0 +1 @@
obj-$(CONFIG_LAN9252) += lan9252.o

View File

@ -0,0 +1,414 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/spi/spi.h>
#include <linux/uaccess.h>
/*
Datasheet : http://ww1.microchip.com/downloads/en/DeviceDoc/
00001909A.pdf
*/
#define LAN9252_MAGIC 'l' //8bit=0~0xff 'l'an9252
#define TEST _IO(LAN9252_MAGIC, 0)
#define LAN9252_LOCK mutex_lock(&lan9252_mutex);
#define LAN9252_UNLOCK mutex_unlock(&lan9252_mutex);
#define DEVICE_NAME "lan9252"
#define LAN9252_MAJOR 153
#define FAST_READ 0x0B
#define FAST_READ_DUMMY 1
struct mutex lock;
static DEFINE_MUTEX(lan9252_mutex);
dev_t id;
static struct device *dev;
static struct class *lan9252_class;
static struct spi_device *lan9252_devices;
static int lan9252_ethercat_probe(struct spi_device *spi);
static int lan9252_ethercat_remove(struct spi_device *spi);
static int lan9252_open(struct inode *inode, struct file *filp)
{
dev_dbg(&lan9252_devices->dev, "%s() called\n", __FUNCTION__);
return 0;
}
static int lan9252_release(struct inode *inode, struct file *filp)
{
dev_dbg(&lan9252_devices->dev, "%s() called\n", __FUNCTION__);
return 0;
}
static loff_t lan9252_llseek(struct file *file, loff_t address,
int whence)
{
int status;
LAN9252_LOCK;
file->f_pos = address;
status = file->f_pos;
LAN9252_UNLOCK;
return status;
}
static int * lan9252_reg_addr_make(int address)
{
int temp;
static int lan9252_reg_addr[2];
#ifdef DEBUG
int i;
#endif
dev_dbg(&lan9252_devices->dev, "%s() called\n", __FUNCTION__);
temp = address & 0xff00;
lan9252_reg_addr[0] = temp >> 8;
temp = address & 0x00ff;
lan9252_reg_addr[1] = temp;
#ifdef DEBUG
for (i=0; i<2; i++)
dev_dbg(&lan9252_devices->dev, "%s() lan9252_reg_addr[%d] = 0x%x\n",
__FUNCTION__, i, lan9252_reg_addr[i]);
#endif
return lan9252_reg_addr;
}
/*
int lan9252_test(void);
Description : Check the connection status of LAN9252
Retrun Value
0 : success
other : fail
Register Type : SYSTEM CONTROL AND STATUS REGISTERS
Register Name(SYMBOL) : BYTE ORDER TEST REGISTER(BYTE_TEST)
Offset : 0x0064
Size : 32bit
Default : 0x87654321
Datasheet description : Chip-level reset/configuration
completion can be determined by first
polling the
Byte Order Test Register(BYTE_TEST).
*/
static int lan9252_test(void)
{
u8 command[4];
u8 test_buffer[4];
int status=0;
#ifdef DEBUG
int i;
#endif
command[0]=FAST_READ;
command[1]=0x00;
command[2]=0x64;
command[3]=FAST_READ_DUMMY;
status = spi_write_then_read(lan9252_devices, &command,
sizeof(command), test_buffer, sizeof(test_buffer));
if (status < 0 ) {
dev_err(&lan9252_devices->dev, "%s() spi_write_then_read "
" failed status=%d\n", __FUNCTION__, status);
return -1;
}
status = spi_write_then_read(lan9252_devices, &command,
sizeof(command), test_buffer, sizeof(test_buffer));
if (status < 0 ) {
dev_err(&lan9252_devices->dev, "%s() spi_write_then_read "
" failed status=%d\n", __FUNCTION__, status);
return -1;
}
#ifdef DEBUG
for (i=0; i<sizeof(test_buffer); i++)
dev_dbg(&lan9252_devices->dev, "%s() test_buffer[%d] = 0x%x\n",
__FUNCTION__, i, test_buffer[i]);
#endif
if (test_buffer[0]==0x21 && test_buffer[1]==0x43 &&
test_buffer[2]==0x65 && test_buffer[3]==0x87)
return 0;
else
return -1;
}
static ssize_t lan9252_read(
struct file *file, char *buffer,
size_t read_buffer_size, loff_t *f_pos)
{
u8 command[4];
u8 *read_buffer;
int status=0;
int *lan9252_reg_read_addr;
#ifdef DEBUG
int i;
#endif
dev_dbg(&lan9252_devices->dev, "%s() called\n", __FUNCTION__);
LAN9252_LOCK;
if (read_buffer_size <= 0) {
dev_err(&lan9252_devices->dev, "read_buffer_size(%d) <= 0 \n",
read_buffer_size);
goto out;
} else {
dev_dbg(&lan9252_devices->dev, "read_buffer_size = %d\n",
read_buffer_size);
}
read_buffer= (u8 *)kmalloc((read_buffer_size) *
sizeof(u32), GFP_KERNEL | GFP_DMA);
if (!read_buffer) {
dev_err(&lan9252_devices->dev, "read_buffer kmalloc error\n");
status = -ENOMEM;
goto out;
}
memset(read_buffer, 0, (read_buffer_size) * sizeof(u8));
lan9252_reg_read_addr = lan9252_reg_addr_make(file->f_pos);
command[0] = FAST_READ;
command[1] = lan9252_reg_read_addr[0];
command[2] = lan9252_reg_read_addr[1];
command[3] = FAST_READ_DUMMY;
#ifdef DEBUG
for (i=0; i<4; i++)
dev_dbg(&lan9252_devices->dev, "%s() command[%d] = 0x%x\n",
__FUNCTION__, i, command[i]);
#endif
status = spi_write_then_read(lan9252_devices, &command,
sizeof(command), read_buffer,read_buffer_size);
if (status < 0 ) {
dev_err(&lan9252_devices->dev, "%s() spi_write_then_read "
"failed status=%d\n", __FUNCTION__, status);
goto kfree_read_buffer;
}
#ifdef DEBUG
for (i=0; i<read_buffer_size; i++)
dev_dbg(&lan9252_devices->dev, "%s() read_buffer[%d] = 0x%x\n",
__FUNCTION__, i, read_buffer[i]);
#endif
if (copy_to_user(buffer, read_buffer, read_buffer_size)) {
dev_err(&lan9252_devices->dev, "%s() copy_to_user failed\n",
__FUNCTION__);
status = -EFAULT;
goto kfree_read_buffer;
}
status = read_buffer_size;
kfree_read_buffer:
kfree(read_buffer);
out:
LAN9252_UNLOCK;
return status;
}
static ssize_t lan9252_write(
struct file *file, const char *command_buff,
size_t command_buff_size, loff_t *f_pos)
{
u8 *command;
int status=0;
#ifdef DEBUG
int i;
#endif
dev_dbg(&lan9252_devices->dev, "%s() called\n", __FUNCTION__);
LAN9252_LOCK;
if (command_buff_size <= 0) {
dev_err(&lan9252_devices->dev, "command_buff_size(%d) <= 0 \n",
command_buff_size);
goto out;
} else {
dev_dbg(&lan9252_devices->dev, "command_buff_size = %d\n",
command_buff_size);
}
command = (u8 *)kmalloc((command_buff_size) *
sizeof(u8), GFP_KERNEL | GFP_DMA);
if (!command) {
dev_err(&lan9252_devices->dev, "write command buffer kmalloc"
" error\n");
status = -ENOMEM;
goto out;
}
memset(command, 0, (command_buff_size) * sizeof(u8));
if (copy_from_user(command, command_buff, command_buff_size)) {
dev_err(&lan9252_devices->dev, "%s() copy_from_user failed\n",
__FUNCTION__);
status = -EFAULT;
goto kfree_command;
}
#ifdef DEBUG
for(i=0;i<command_buff_size;i++)
dev_dbg(&lan9252_devices->dev, "command[%d]=0x%x\n", i,
command[i]);
#endif
status = spi_write_then_read(lan9252_devices, command,
command_buff_size, NULL, 0);
if (status < 0 ) {
dev_err(&lan9252_devices->dev, "%s() spi_write_then_read "
"failed status=%d\n", __FUNCTION__, status);
goto kfree_command;
}
kfree_command:
kfree(command);
out:
LAN9252_UNLOCK;
return status;
}
static long lan9252_ioctl(struct file *file, unsigned int cmd,
unsigned long argument)
{
int status;
LAN9252_LOCK;
switch (cmd) {
case TEST:
status=lan9252_test();
break;
default:
status=0;
break;
}
LAN9252_UNLOCK;
return status;
}
static const struct spi_device_id lan9252_id_table[] = {
{ "lan9252", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, lan9252_id_table);
static const struct file_operations lan9252_fops = {
.owner = THIS_MODULE,
.open = lan9252_open,
.release = lan9252_release,
.llseek = lan9252_llseek,
.write = lan9252_write,
.read = lan9252_read,
.unlocked_ioctl = lan9252_ioctl,
};
static struct spi_driver lan9252_ethercat_driver = {
.driver = {
.name = DEVICE_NAME,
},
.id_table = lan9252_id_table,
.probe = lan9252_ethercat_probe,
.remove = lan9252_ethercat_remove,
};
static int lan9252_ethercat_probe(struct spi_device *spi)
{
int status;
dev_dbg(&spi->dev, "%s() called\n", __FUNCTION__);
mutex_init(&lock);
lan9252_devices = spi;
if(lan9252_test())
dev_warn(&lan9252_devices->dev, "lan9252 not connected\n");
if (register_chrdev(LAN9252_MAJOR,
lan9252_ethercat_driver.driver.name, &lan9252_fops)) {
dev_err(&lan9252_devices->dev, "unable to get major %d for "
, LAN9252_MAJOR);
status = -ENODEV;
goto register_chrdev_fail;
}
lan9252_class = class_create(THIS_MODULE,
lan9252_ethercat_driver.driver.name);
if (IS_ERR(lan9252_class)) {
status = PTR_ERR(lan9252_class);
goto class_create_fail;
}
id = MKDEV(LAN9252_MAJOR, 0);
dev = device_create(lan9252_class, NULL, id, NULL,
lan9252_ethercat_driver.driver.name);
if (IS_ERR(dev)) {
status = PTR_ERR(dev);
dev_err(dev, "device_create error %d\n", status);
goto device_create_fail;
}
dev_dbg(&lan9252_devices->dev, "spi->max_speed_hz=%d"
" spi->bits_per_word=%d spi->mode=%d\n", spi->max_speed_hz,
spi->bits_per_word, spi->mode);
dev_dbg(&lan9252_devices->dev, "spi->chip_select=%d spi->cs_gpio=%d\n",
spi->chip_select, spi->cs_gpio);
dev_info(&lan9252_devices->dev, "Probed\n");
return 0;
device_create_fail:
class_destroy(lan9252_class);
class_create_fail:
unregister_chrdev(LAN9252_MAJOR,
lan9252_ethercat_driver.driver.name);
register_chrdev_fail:
dev_err(&lan9252_devices->dev, "Probed failed : %d\n", status);
return status;
}
static int lan9252_ethercat_remove(struct spi_device *spi)
{
dev_dbg(&lan9252_devices->dev, "%s() called\n", __FUNCTION__);
device_destroy(lan9252_class, id);
class_destroy(lan9252_class);
unregister_chrdev(LAN9252_MAJOR,
lan9252_ethercat_driver.driver.name);
dev_info(&lan9252_devices->dev, "Removed\n");
return 0;
}
module_spi_driver(lan9252_ethercat_driver);
MODULE_AUTHOR("tykwon@m2i.co.kr");
MODULE_DESCRIPTION("Microchip LAN9252 Ethercat Driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,13 @@
* Microchip LAN9252 stand-alone EtherCAT slave controller device tree bindings
Required properties:
- compatible: Should be "lan9252".
- spi-max-frequency : Max spi frequency to use
- reg: SPI chip select.
Example:
ethercat: lan9252@1 {
compatible = "lan9252";
spi-max-frequency = <20000000>;
reg = <1>;
};

View File

@ -0,0 +1,461 @@
/*
* SOES Simple Open EtherCAT Slave
*
* Copyright (C) 2007-2017 Arthur Ketels
* Copyright (C) 2012-2017 rt-labs.
*
* SOES is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* SOES 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.
*
* As a special exception, if other files instantiate templates or use macros
* or inline functions from this file, or you compile this file and link it
* with other works to produce a work based on this file, this file does not
* by itself cause the resulting work to be covered by the GNU General Public
* License. However the source code for this file must still be made available
* in accordance with section (3) of the GNU General Public License.
*
* This exception does not invalidate any other reasons why a work based on
* this file might be covered by the GNU General Public License.
*
* The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual
* property of, and protected by Beckhoff Automation GmbH.
*/
/** \file
* \brief
* ESC hardware layer functions for LAN9252.
*
* Function to read and write commands to the ESC. Used to read/write ESC
* registers and memory.
*/
#include "utypes.h"
#include "esc.h"
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#define BIT(x) 1 << (x)
#define ESC_CMD_SERIAL_WRITE 0x02
#define ESC_CMD_SERIAL_READ 0x03
#define ESC_CMD_FAST_READ 0x0B
#define ESC_CMD_RESET_SQI 0xFF
#define ESC_CMD_FAST_READ_DUMMY 1
#define ESC_CMD_ADDR_INC BIT(6)
#define ESC_PRAM_RD_FIFO_REG 0x000
#define ESC_PRAM_WR_FIFO_REG 0x020
#define ESC_PRAM_RD_ADDR_LEN_REG 0x308
#define ESC_PRAM_RD_CMD_REG 0x30C
#define ESC_PRAM_WR_ADDR_LEN_REG 0x310
#define ESC_PRAM_WR_CMD_REG 0x314
#define ESC_PRAM_CMD_BUSY BIT(31)
#define ESC_PRAM_CMD_ABORT BIT(30)
#define ESC_PRAM_CMD_CNT(x) ((x >> 8) & 0x1F)
#define ESC_PRAM_CMD_AVAIL BIT(0)
#define ESC_PRAM_SIZE(x) ((x) << 16)
#define ESC_PRAM_ADDR(x) ((x) << 0)
#define ESC_CSR_DATA_REG 0x300
#define ESC_CSR_CMD_REG 0x304
#define ESC_CSR_CMD_BUSY BIT(31)
#define ESC_CSR_CMD_READ (BIT(31) | BIT(30))
#define ESC_CSR_CMD_WRITE BIT(31)
#define ESC_CSR_CMD_SIZE(x) (x << 16)
#define ESC_RESET_CTRL_REG 0x1F8
#define ESC_RESET_CTRL_RST BIT(6)
static int lan9252 = -1;
/* lan9252 singel write */
static void lan9252_write_32 (uint16_t address, uint32_t val)
{
uint8_t data[7];
data[0] = ESC_CMD_SERIAL_WRITE;
data[1] = ((address >> 8) & 0xFF);
data[2] = (address & 0xFF);
data[3] = (val & 0xFF);
data[4] = ((val >> 8) & 0xFF);
data[5] = ((val >> 16) & 0xFF);
data[6] = ((val >> 24) & 0xFF);
/* Write data */
write (lan9252, data, sizeof(data));
}
/* lan9252 single read */
static uint32_t lan9252_read_32 (uint32_t address)
{
uint8_t data[2];
uint8_t result[4];
uint16_t lseek_addr;
data[0] = ((address >>8) & 0xFF);
data[1] = (address & 0xFF);
lseek_addr=((uint16_t)data[0] << 8) | data[1];
lseek (lan9252, lseek_addr, SEEK_SET);
read (lan9252, result, sizeof(result));
return ((result[3] << 24) |
(result[2] << 16) |
(result[1] << 8) |
result[0]);
}
/* ESC read CSR function */
static void ESC_read_csr (uint16_t address, void *buf, uint16_t len)
{
uint32_t value;
value = (ESC_CSR_CMD_READ | ESC_CSR_CMD_SIZE(len) | address);
lan9252_write_32(ESC_CSR_CMD_REG, value);
do
{
value = lan9252_read_32(ESC_CSR_CMD_REG);
} while(value & ESC_CSR_CMD_BUSY);
value = lan9252_read_32(ESC_CSR_DATA_REG);
memcpy(buf, (uint8_t *)&value, len);
}
/* ESC write CSR function */
static void ESC_write_csr (uint16_t address, void *buf, uint16_t len)
{
uint32_t value;
memcpy((uint8_t*)&value, buf,len);
lan9252_write_32(ESC_CSR_DATA_REG, value);
value = (ESC_CSR_CMD_WRITE | ESC_CSR_CMD_SIZE(len) | address);
lan9252_write_32(ESC_CSR_CMD_REG, value);
do
{
value = lan9252_read_32(ESC_CSR_CMD_REG);
} while(value & ESC_CSR_CMD_BUSY);
}
/* ESC read process data ram function */
static void ESC_read_pram (uint16_t address, void *buf, uint16_t len)
{
uint32_t value;
uint8_t * temp_buf = buf;
uint16_t byte_offset = 0;
uint8_t fifo_cnt, first_byte_position, temp_len, data[2];
uint8_t *buffer;
int i, array_size, size;
float quotient,remainder;
uint32_t temp;
value = ESC_PRAM_CMD_ABORT;
lan9252_write_32(ESC_PRAM_RD_CMD_REG, value);
do
{
value = lan9252_read_32(ESC_PRAM_RD_CMD_REG);
}while(value & ESC_PRAM_CMD_BUSY);
value = ESC_PRAM_SIZE(len) | ESC_PRAM_ADDR(address);
lan9252_write_32(ESC_PRAM_RD_ADDR_LEN_REG, value);
value = ESC_PRAM_CMD_BUSY;
lan9252_write_32(ESC_PRAM_RD_CMD_REG, value);
do
{
value = lan9252_read_32(ESC_PRAM_RD_CMD_REG);
}while((value & ESC_PRAM_CMD_AVAIL) == 0);
/* Fifo count */
fifo_cnt = ESC_PRAM_CMD_CNT(value);
/* Read first value from FIFO */
value = lan9252_read_32(ESC_PRAM_RD_FIFO_REG);
fifo_cnt--;
/* Find out first byte position and adjust the copy from that
* according to LAN9252 datasheet and MicroChip SDK code
*/
first_byte_position = (address & 0x03);
temp_len = ((4 - first_byte_position) > len) ? len : (4 - first_byte_position);
memcpy(temp_buf ,((uint8_t *)&value + first_byte_position), temp_len);
len -= temp_len;
byte_offset += temp_len;
/* Continue reading until we have read len */
if (len > 0){
quotient = len/4;
remainder = len%4;
if (remainder == 0)
array_size = quotient;
else
array_size = quotient+1;
size = 4*array_size;
buffer = (uint8_t *)malloc(size);
buffer[0] = size;
memset(buffer,0,size);
lseek (lan9252, ESC_PRAM_RD_FIFO_REG, SEEK_SET);
read (lan9252, buffer, size);
while(len > 0)
{
for (i=0; i<size; i=i+4) {
temp_len = (len > 4) ? 4: len;
temp = buffer[i] | (buffer[i+1] << 8) | (buffer[i+2] << 16) | (buffer[i+3] << 24);
memcpy(temp_buf + byte_offset ,&temp, temp_len);
fifo_cnt--;
len -= temp_len;
byte_offset += temp_len;
}
}
free(buffer);
}
}
/* ESC write process data ram function */
static void ESC_write_pram (uint16_t address, void *buf, uint16_t len)
{
uint32_t value;
uint8_t * temp_buf = buf;
uint16_t byte_offset = 0;
uint8_t fifo_cnt, first_byte_position, temp_len, data[3];
uint8_t *buffer;
int i, array_size, size;
float quotient,remainder;
value = ESC_PRAM_CMD_ABORT;
lan9252_write_32(ESC_PRAM_WR_CMD_REG, value);
do
{
value = lan9252_read_32(ESC_PRAM_WR_CMD_REG);
}while(value & ESC_PRAM_CMD_BUSY);
value = ESC_PRAM_SIZE(len) | ESC_PRAM_ADDR(address);
lan9252_write_32(ESC_PRAM_WR_ADDR_LEN_REG, value);
value = ESC_PRAM_CMD_BUSY;
lan9252_write_32(ESC_PRAM_WR_CMD_REG, value);
do
{
value = lan9252_read_32(ESC_PRAM_WR_CMD_REG);
}while((value & ESC_PRAM_CMD_AVAIL) == 0);
/* Fifo count */
fifo_cnt = ESC_PRAM_CMD_CNT(value);
/* Find out first byte position and adjust the copy from that
* according to LAN9252 datasheet
*/
first_byte_position = (address & 0x03);
temp_len = ((4 - first_byte_position) > len) ? len : (4 - first_byte_position);
memcpy(((uint8_t *)&value + first_byte_position), temp_buf, temp_len);
/* Write first value from FIFO */
lan9252_write_32(ESC_PRAM_WR_FIFO_REG, value);
len -= temp_len;
byte_offset += temp_len;
fifo_cnt--;
if (len > 0){
quotient = len/4;
remainder = len%4;
if (remainder == 0)
array_size = quotient;
else
array_size = quotient+1;
size = 3+4*array_size;
buffer = (uint8_t *)malloc(size);
buffer[0] = size;
memset(buffer,0,size);
buffer[0] = ESC_CMD_SERIAL_WRITE;
buffer[1] = ((ESC_PRAM_WR_FIFO_REG >> 8) & 0xFF);
buffer[2] = (ESC_PRAM_WR_FIFO_REG & 0xFF);
while(len > 0)
{
for (i=3; i<size; i=i+4) {
temp_len = (len > 4) ? 4 : len;
memcpy((uint8_t *)&value, (temp_buf + byte_offset), temp_len);
buffer[i] = (value & 0xFF);
buffer[i+1] = ((value >> 8) & 0xFF);
buffer[i+2] = ((value >> 16) & 0xFF);
buffer[i+3] = ((value >> 24) & 0xFF);
fifo_cnt--;
len -= temp_len;
byte_offset += temp_len;
}
}
write (lan9252, buffer, size);
free(buffer);
}
}
/** ESC read function used by the Slave stack.
*
* @param[in] address = address of ESC register to read
* @param[out] buf = pointer to buffer to read in
* @param[in] len = number of bytes to read
*/
void ESC_read (uint16_t address, void *buf, uint16_t len)
{
/* Select Read function depending on address, process data ram or not */
if (address >= 0x1000)
{
ESC_read_pram(address, buf, len);
}
else
{
uint16_t size;
uint8_t *temp_buf = (uint8_t *)buf;
while(len > 0)
{
/* We write maximum 4 bytes at the time */
size = (len > 4) ? 4 : len;
/* Make size aligned to address according to LAN9252 datasheet
* Table 12-14 EtherCAT CSR Address VS size and MicroChip SDK code
*/
/* If we got an odd address size is 1 , 01b 11b is captured */
if(address & BIT(0))
{
size = 1;
}
/* If address 1xb and size != 1 and 3 , allow size 2 else size 1 */
else if (address & BIT(1))
{
size = (size & BIT(0)) ? 1 : 2;
}
/* size 3 not valid */
else if (size == 3)
{
size = 1;
}
/* else size is kept AS IS */
ESC_read_csr(address, temp_buf, size);
/* next address */
len -= size;
temp_buf += size;
address += size;
}
}
/* To mimic the ET1100 always providing AlEvent on every read or write */
ESC_read_csr(ESCREG_ALEVENT,(void *)&ESCvar.ALevent,sizeof(ESCvar.ALevent));
ESCvar.ALevent = etohs (ESCvar.ALevent);
}
/** ESC write function used by the Slave stack.
*
* @param[in] address = address of ESC register to write
* @param[out] buf = pointer to buffer to write from
* @param[in] len = number of bytes to write
*/
void ESC_write (uint16_t address, void *buf, uint16_t len)
{
/* Select Write function depending on address, process data ram or not */
if (address >= 0x1000)
{
ESC_write_pram(address, buf, len);
}
else
{
uint16_t size;
uint8_t *temp_buf = (uint8_t *)buf;
while(len > 0)
{
/* We write maximum 4 bytes at the time */
size = (len > 4) ? 4 : len;
/* Make size aligned to address according to LAN9252 datasheet
* Table 12-14 EtherCAT CSR Address VS size and MicroChip SDK code
*/
/* If we got an odd address size is 1 , 01b 11b is captured */
if(address & BIT(0))
{
size = 1;
}
/* If address 1xb and size != 1 and 3 , allow size 2 else size 1 */
else if (address & BIT(1))
{
size = (size & BIT(0)) ? 1 : 2;
}
/* size 3 not valid */
else if (size == 3)
{
size = 1;
}
/* else size is kept AS IS */
ESC_write_csr(address, temp_buf, size);
/* next address */
len -= size;
temp_buf += size;
address += size;
}
}
/* To mimic the ET1x00 always providing AlEvent on every read or write */
ESC_read_csr(ESCREG_ALEVENT,(void *)&ESCvar.ALevent,sizeof(ESCvar.ALevent));
ESCvar.ALevent = etohs (ESCvar.ALevent);
}
/* Un-used due to evb-lan9252-digio not havning any possability to
* reset except over SPI.
*/
void ESC_reset (void)
{
}
void ESC_init (const void * arg)
{
uint32_t value;
const char * spi_name = (char *)arg;
lan9252 = open (spi_name, O_RDWR, 0);
/* Reset the ecat core here due to evb-lan9252-digio not having any GPIO
* for that purpose.
*/
lan9252_write_32(ESC_RESET_CTRL_REG,ESC_RESET_CTRL_RST);
do
{
value = lan9252_read_32(ESC_CSR_CMD_REG);
} while(value & ESC_RESET_CTRL_RST);
}

View File

@ -8,7 +8,11 @@ extern "C"
#include <assert.h>
#include <stdint.h>
#include <machine/endian.h>
#ifdef __linux__
#include <endian.h>
#else
#include <machine/endian.h>
#endif
#define CC_PACKED_BEGIN
#define CC_PACKED_END