The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang...

26
The Shiny New I2C Slave Framework Wolfram Sang Consultant/Renesas Kernel Team 6.10.2015, ELCE15 Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 1 / 26

Transcript of The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang...

Page 1: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

The Shiny New I2C Slave Framework

Wolfram SangConsultant/Renesas Kernel Team

6.10.2015, ELCE15

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 1 / 26

Page 2: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

A typical I2C bus

VddSDASCL

Rp

LinuxMaster

μCSlaveSlave

ADCSlaveDAC

1

1picture based on this one by Colin M.L. BurnettWolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 2 / 26

Page 3: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

The new era :)

VddSDASCL

Rp

LinuxMa./Sl.

LinuxMa./Sl.Slave

ADCSlaveDAC

2

2picture based on this one by Colin M.L. BurnettWolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 3 / 26

Page 4: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Finally…

At this time, Linux only operates I2C (or SMBus) inmaster mode; you can’t use these APIs to make a Linuxsystem behave as a slave/device, either to speak acustom protocol or to emulate some other device.

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 4 / 26

Page 5: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Use cases

data delivery (sensor like)configuration (codec like)embedded controllers (e.g. nvec)avoid multi-master

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 5 / 26

Page 6: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Data flow

User Backend Driver Controller

kernel driver,sysfs,

char device,...

I2C slaveevents

IO registers

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 6 / 26

Page 7: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Driver side

We need support from the I2C bus driveractivating slave support in the core is not enoughusually extension to the I2C master driverno slave only solutions please

watch your PM settingsa slave always needs to listen

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 7 / 26

Page 8: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Registering a slavestatic int rcar_reg_slave(struct i2c_client *slave){

struct rcar_i2c_priv *priv = i2c_get_adapdata(slave->adapter);

if (priv->slave)return -EBUSY;

if (slave->flags & I2C_CLIENT_TEN)return -EAFNOSUPPORT;

pm_runtime_forbid(rcar_i2c_priv_to_dev(priv));

priv->slave = slave;rcar_i2c_write(priv, ICSAR, slave->addr);rcar_i2c_write(priv, ICSSR, 0);rcar_i2c_write(priv, ICSIER, SAR | SSR);rcar_i2c_write(priv, ICSCR, SIE | SDBS);

return 0;}

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 8 / 26

Page 9: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Slave events

Handler functionret = i2c_slave_event(slave, event, &val)

links driver and backendval carries the data. It is bidirectional.usually called from interrupt context!

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 9 / 26

Page 10: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Slave events (master writes)

S Addr+W Data A/NA ... P

I2C_SLAVE_WRITE_REQUESTED I2C_SLAVE_STOP

I2C_SLAVE_WRITE_RECEIVEDval = byte from master, ret = 0/-ERRNO

val = unused, ret = 0 val = unused, ret = 0

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 10 / 26

Page 11: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Slave events (master reads)

S Addr+R Data A/NA ... P

I2C_SLAVE_READ_REQUESTED I2C_SLAVE_STOP

I2C_SLAVE_READ_PROCESSEDval = byte to master, ret = 0

val = byte to master, ret = 0 val = unused, ret = 0

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 11 / 26

Page 12: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Slave interrupt handler I

static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv){

u32 ssr_raw, ssr_filtered;u8 value;

ssr_raw = rcar_i2c_read(priv, ICSSR) & 0xff;ssr_filtered = ssr_raw & rcar_i2c_read(priv, ICSIER);

if (!ssr_filtered)return false;

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 12 / 26

Page 13: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Slave interrupt handler II

/* address detected */if (ssr_filtered & SAR) {

/* read or write request */if (ssr_raw & STM) {

i2c_slave_event(priv->slave, I2C_SLAVE_READ_REQUESTED, &value);rcar_i2c_write(priv, ICRXTX, value);rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR);

} else {i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value);rcar_i2c_read(priv, ICRXTX); /* dummy read */rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);

}

rcar_i2c_write(priv, ICSSR, ~SAR & 0xff);}

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 13 / 26

Page 14: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Slave interrupt handler III

/* master sent stop */if (ssr_filtered & SSR) {

i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);rcar_i2c_write(priv, ICSIER, SAR | SSR);rcar_i2c_write(priv, ICSSR, ~SSR & 0xff);

}

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 14 / 26

Page 15: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Slave interrupt handler IV

/* master wants to write to us */if (ssr_filtered & SDR) {

int ret;

value = rcar_i2c_read(priv, ICRXTX);ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value);/* Send NACK in case of error */rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0));rcar_i2c_write(priv, ICSSR, ~SDR & 0xff);

}

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 15 / 26

Page 16: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Slave interrupt handler V

/* master wants to read from us */if (ssr_filtered & SDE) {

i2c_slave_event(priv->slave, I2C_SLAVE_READ_PROCESSED, &value);rcar_i2c_write(priv, ICRXTX, value);rcar_i2c_write(priv, ICSSR, ~SDE & 0xff);

}

return true;}

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 16 / 26

Page 17: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Backends

are standard i2c driversare normally matched to i2c clientsare HW independentprovide a callback to handle slave events

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 17 / 26

Page 18: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Backend driver I

static int i2c_slave_8bit_seconds_slave_cb(struct i2c_client *client,enum i2c_slave_event event, u8 *val)

{switch (event) {case I2C_SLAVE_READ_REQUESTED:case I2C_SLAVE_READ_PROCESSED:

/* Always get the most recent value */*val = get_seconds() & 0xff;break;

case I2C_SLAVE_WRITE_REQUESTED:case I2C_SLAVE_WRITE_RECEIVED:case I2C_SLAVE_STOP:default:

break;}

return 0;}

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 18 / 26

Page 19: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Backend driver II

static int i2c_slave_8bit_seconds_probe(struct i2c_client *client,const struct i2c_device_id *id)

{return i2c_slave_register(client, i2c_slave_8bit_seconds_slave_cb);

};

static int i2c_slave_8bit_seconds_remove(struct i2c_client *client){

i2c_slave_unregister(client);return 0;

}

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 19 / 26

Page 20: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

The ”read pointer” problem

...case I2C_SLAVE_READ_PROCESSED:

/* The previous byte made it to the bus, get next one */eeprom->buffer_idx++;/* fallthrough */

case I2C_SLAVE_READ_REQUESTED:spin_lock(&eeprom->buffer_lock);*val = eeprom->buffer[eeprom->buffer_idx];spin_unlock(&eeprom->buffer_lock);/** Do not increment buffer_idx here, because we don't know if* this byte will be actually used. Read Linux I2C slave docs* for details.*/

break;...

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 20 / 26

Page 21: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Current status

Drivers: RCar, (Tegra), ((Davinci))

Backend: EEPROM/memory simulator

Devicetree: bindings clear \o/

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 21 / 26

Page 22: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Address spacesAvoid address collisions. Enable loopbacks.Devicetree

I2C_TEN_BIT_ADDRESSaddress space: 0xa000 - 0xa3ff

I2C_OWN_SLAVE_ADDRESSaddress space += 0x1000

Example:reg = <(I2C_OWN_SLAVE_ADDRESS | 0x42)>;

Run time instantiationecho slave-24c02 0x1064

> /sys/bus/i2c/devices/i2c-1/new_device

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 22 / 26

Page 23: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Next steps

more driver support

more backends (if there is a user)

no new features (unless there is a use case)

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 23 / 26

Page 24: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Thanks! <3

Renesasfor funding this upstream solution

Renesas Kernel Teamespecially Geert and Laurent for thorough review

Uwe Kleine-Königfor in-depth discussions

Andrey Daninfor the Tegra slave implementation and nvec backend port

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 24 / 26

Page 25: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

Demo!

At the showcase this evening

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 25 / 26

Page 26: The Shiny New I2C Slave Framework - eLinux.org · The Shiny New I2C Slave Framework Wolfram Sang ... sysfs, char device,... I2C slave ... spin_lock(&eeprom->buffer_lock);

The End

Thank you for your attention!

Questions? Comments?right nowat the showcase this eveningor anytime at this [email protected]

Wolfram Sang ([email protected]) The Shiny New I2C Slave Framework 6.10.2015, ELCE15 26 / 26