Message ID | 20190812235237.21797-1-max@enpas.org (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
Series | [v2,1/4] i2c/busses: Add i2c-icy for I2C on m68k/Amiga | expand |
Hi Max, On Tue, Aug 13, 2019 at 1:53 AM Max Staudt <max@enpas.org> wrote: > This is the i2c-icy driver for the ICY board for Amiga computers. > It connects a PCF8584 I2C controller to the Zorro bus, providing I2C > connectivity. The original documentation can be found on Aminet: > > https://aminet.net/package/docs/hard/icy > > IRQ support is currently not implemented, as i2c-algo-pcf is built for > the ISA bus and a straight implementation of the same stack locks up a > Zorro machine. > > v2: Matched function names to callbacks from i2c-algo-pcf > Used z_readb()/z_writeb() > Removed BROKEN_ON_SMP in Kconfig > Moved LTC2990 to a separate commit > > Signed-off-by: Max Staudt <max@enpas.org> Thanks for the update! > --- /dev/null > +++ b/drivers/i2c/busses/i2c-icy.c > @@ -0,0 +1,189 @@ > + dev_info(&z->dev, "ICY I2C controller at %#x, IRQ not implemented\n", > + z->resource.start); z->resource.start has type phys_addr_t, so you should pas a reference, and use %pa to print it. Alternatively, you can print the full resource using %pR. See Documentation/core-api/printk-formats.rst > + > + return 0; > +} The rest looks fine to me. Gr{oetje,eeting}s, Geert
On 08/13/2019 09:08 AM, Geert Uytterhoeven wrote: >> + dev_info(&z->dev, "ICY I2C controller at %#x, IRQ not implemented\n", >> + z->resource.start); > > z->resource.start has type phys_addr_t, so you should pas a reference, and > use %pa to print it. > Alternatively, you can print the full resource using %pR. > See Documentation/core-api/printk-formats.rst Ack, this snuck in from the early days. Thanks for pointing this out! Max
Hi, Thanks for the patch. It looks mostly good. > +static int clock = 0x1c; > +module_param(clock, int, 0444); 'clock' determines the bus speed? > + i2c->adapter.class = I2C_CLASS_DEPRECATED; This is only needed for drivers which used to have a class and decided to drop it. You can leave it empty. > + algo_data->data = (void *)i2c; You don't need the cast, do you? > +MODULE_LICENSE("GPL"); Your SPDX header says GPL 2.0 only. Kind regards, Wolfram
Hi Wolfram, Thanks for your input! Replies below. On 08/14/2019 09:47 PM, Wolfram Sang wrote: >> +static int clock = 0x1c; >> +module_param(clock, int, 0444); > > 'clock' determines the bus speed? Yes, but it also determines the frequency of the oscillator driving the PCF8584. It doesn't usually need to be touched, the current setting drives at the maximum I2C bus speed, with the maximum oscillator (12 MHz). I kept it in because i2c-elektor also exposes it in the same way, and it seems useful. >> + i2c->adapter.class = I2C_CLASS_DEPRECATED; > > This is only needed for drivers which used to have a class and decided > to drop it. You can leave it empty. Thanks, I'll drop it. >> + algo_data->data = (void *)i2c; > > You don't need the cast, do you? True. Dropped, thanks. >> +MODULE_LICENSE("GPL"); > > Your SPDX header says GPL 2.0 only. Thanks! I'll change it to "GPL v2", but unfortunately there is no option for "only" in include/linux/module.h. Cheers Max
> I kept it in because i2c-elektor also exposes it in the same way, and > it seems useful. Yeah, I noticed. I don't know how useful it is in practice (same for the getown callback) but I don't have better ideas, so let's just keep this to be consistent. > > Your SPDX header says GPL 2.0 only. > > Thanks! I'll change it to "GPL v2", but unfortunately there is no > option for "only" in include/linux/module.h. That's the correct option. Thanks!
On 08/15/2019 09:12 AM, Wolfram Sang wrote: >> I kept it in because i2c-elektor also exposes it in the same way, and >> it seems useful. > > Yeah, I noticed. I don't know how useful it is in practice (same for the > getown callback) but I don't have better ideas, so let's just keep this > to be consistent. Well, the other option is to remove it, and then add it back once somebody complains - which is unlikely to happen. The clock parameter is PCF8584 specific anyway, and I think removing it is a good option, as I've done the same with getown() (where in i2c-elektor, 'own' sets the PCF8584's own address). Question is, if I remove the parameter, I'd like it to be non-destructive. Do you know of anything that can go wrong if the I2C master is running the bus on a wrong clock? Thanks Max
> Well, the other option is to remove it, and then add it back once > somebody complains - which is unlikely to happen. The clock parameter > is PCF8584 specific anyway, and I think removing it is a good option, My suggestion is to do that incrementally. First, get your driver accepted. Second, do the cleanups which affect elektor as well later. > as I've done the same with getown() (where in i2c-elektor, 'own' sets > the PCF8584's own address). I wondered about that. Can the PCF8584 really act as a slave, too? Somewhen I need to check its datasheet. > Question is, if I remove the parameter, I'd like it to be > non-destructive. Do you know of anything that can go wrong if the I2C > master is running the bus on a wrong clock? Not sure if I understand you correctly, but if the bus freq is too fast then devices won't respond. Too slow is not a problem.
On 08/15/2019 01:48 PM, Wolfram Sang wrote: >> Well, the other option is to remove it, and then add it back once >> somebody complains - which is unlikely to happen. The clock parameter >> is PCF8584 specific anyway, and I think removing it is a good option, > > My suggestion is to do that incrementally. First, get your driver > accepted. Second, do the cleanups which affect elektor as well later. My suggestion is to not touch i2c-elektor at all for now, and remove the 'clock' parameter from the first iteration of i2c-icy. It can be added back in case someone complains, which I deem unlikely. >> as I've done the same with getown() (where in i2c-elektor, 'own' sets >> the PCF8584's own address). > > I wondered about that. Can the PCF8584 really act as a slave, too? > Somewhen I need to check its datasheet. Yes it can, but this driver does not implement this. In fact, I just remembered that the own address, while set, is not used at all in master mode! Quote from the datasheet: https://www.nxp.com/docs/en/data-sheet/PCF8584.pdf 6.4 Own address register S0' When the PCF8584 is addressed as slave, this register must be loaded with the 7-bit I 2 C-bus address to which the PCF8584 is to respond. During initialization, the own address register S0' must be written to, regardless whether it is later used. >> Question is, if I remove the parameter, I'd like it to be >> non-destructive. Do you know of anything that can go wrong if the I2C >> master is running the bus on a wrong clock? > > Not sure if I understand you correctly, but if the bus freq is too fast > then devices won't respond. Too slow is not a problem. Okay, so we don't care. Cool, then it's safe to kick the 'clock' parameter from i2c-icy. All 2019 boards (which should be the vast majority in existence) came with a 12 MHz oscillator AFAIK, so the default should be good. Max
> My suggestion is to not touch i2c-elektor at all for now, and remove > the 'clock' parameter from the first iteration of i2c-icy. It can be > added back in case someone complains, which I deem unlikely. Full ack. > When the PCF8584 is addressed as slave, this register > must be loaded with the 7-bit I 2 C-bus address to which the > PCF8584 is to respond. During initialization, the own > address register S0' must be written to, regardless > whether it is later used. I see. It must be written a non-zero value to leave the monitor mode. But this really needs no callback, we can hardcode any non-zero value. If slave support is (ever) to be implemented, the own address will come from the I2C core. > Okay, so we don't care. Cool, then it's safe to kick the 'clock' > parameter from i2c-icy. All 2019 boards (which should be the vast > majority in existence) came with a 12 MHz oscillator AFAIK, so the > default should be good. Most drivers don't allow users to change the bus speed, so I think it is safe to remove.
On 08/15/2019 02:04 PM, Wolfram Sang wrote: >> When the PCF8584 is addressed as slave, this register >> must be loaded with the 7-bit I 2 C-bus address to which the >> PCF8584 is to respond. During initialization, the own >> address register S0' must be written to, regardless >> whether it is later used. > > I see. It must be written a non-zero value to leave the monitor mode. > But this really needs no callback, we can hardcode any non-zero value. > If slave support is (ever) to be implemented, the own address will come > from the I2C core. The callback, just like getclock(), is from the existing i2c-algo-pcf, which I don't want to touch right now. So I'm afraid it has to stay, even if it returns a fixed number. Touching or forking i2c-algo-pcf will be necessary in order to implement IRQ support, if I ever get around to it. I've wasted too much time on debugging IRQ support, and would rather do it another time, if ever ;) I've left a comment block at the start of i2c-icy.c for anyone interested in the gory details. If this is okay with you, I'll send another round of patches. :) Thanks! Max
> The callback, just like getclock(), is from the existing i2c-algo-pcf, > which I don't want to touch right now. So I'm afraid it has to stay, > even if it returns a fixed number. Sure. I was just thinking loud and did not expect you to do it. Maybe I will do it once your driver is upstream. > Touching or forking i2c-algo-pcf will be necessary in order to > implement IRQ support, if I ever get around to it. I've wasted too > much time on debugging IRQ support, and would rather do it another > time, if ever ;) I've left a comment block at the start of i2c-icy.c > for anyone interested in the gory details. Yeah, I read it. I like such documentation. Really helpful! > If this is okay with you, I'll send another round of patches. :) Perfect!
diff --git a/MAINTAINERS b/MAINTAINERS index 1be025959..70336c083 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7705,6 +7705,12 @@ S: Maintained F: drivers/mfd/lpc_ich.c F: drivers/gpio/gpio-ich.c +ICY I2C DRIVER +M: Max Staudt <max@enpas.org> +L: linux-i2c@vger.kernel.org +S: Maintained +F: drivers/i2c/busses/i2c-icy.c + IDE SUBSYSTEM M: "David S. Miller" <davem@davemloft.net> L: linux-ide@vger.kernel.org diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index ee5dfb5ae..9e57e1101 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1300,6 +1300,17 @@ config I2C_ELEKTOR This support is also available as a module. If so, the module will be called i2c-elektor. +config I2C_ICY + tristate "ICY Zorro card" + depends on ZORRO + select I2C_ALGOPCF + help + This supports the PCF8584 Zorro bus I2C adapter, known as ICY. + Say Y if you own such an adapter. + + This support is also available as a module. If so, the module + will be called i2c-icy. + config I2C_MLXCPLD tristate "Mellanox I2C driver" depends on X86_64 diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index a3245231b..d0e1c3d4e 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -139,6 +139,7 @@ obj-$(CONFIG_I2C_BCM_KONA) += i2c-bcm-kona.o obj-$(CONFIG_I2C_BRCMSTB) += i2c-brcmstb.o obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o +obj-$(CONFIG_I2C_ICY) += i2c-icy.o obj-$(CONFIG_I2C_MLXCPLD) += i2c-mlxcpld.o obj-$(CONFIG_I2C_OPAL) += i2c-opal.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o diff --git a/drivers/i2c/busses/i2c-icy.c b/drivers/i2c/busses/i2c-icy.c new file mode 100644 index 000000000..7910f035b --- /dev/null +++ b/drivers/i2c/busses/i2c-icy.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * I2C driver for stand-alone PCF8584 style adapters on Zorro cards + * + * Original ICY documentation can be found on Aminet: + * https://aminet.net/package/docs/hard/icy + * + * There has been a modern community re-print of this design in 2019: + * https://www.a1k.org/forum/index.php?threads/70106/ + * + * The card is basically a Philips PCF8584 connected straight to the + * beginning of the AutoConfig'd address space (register S1 on base+2), + * with /INT on /INT2 on the Zorro bus. + * + * Copyright (c) 2019 Max Staudt <max@enpas.org> + * + * This started as a fork of i2c-elektor.c and has evolved since. + * Thanks go to its authors for providing a base to grow on. + * + * + * IRQ support is currently not implemented. + * + * As it turns out, i2c-algo-pcf is really written with i2c-elektor's + * edge-triggered ISA interrupts in mind, while the Amiga's Zorro bus has + * level-triggered interrupts. This means that once an interrupt occurs, we + * have to tell the PCF8584 to shut up immediately, or it will keep the + * interrupt line busy and cause an IRQ storm. + + * However, because of the PCF8584's host-side protocol, there is no good + * way to just quieten it without side effects. Rather, we have to perform + * the next read/write operation straight away, which will reset the /INT + * pin. This entails re-designing the core of i2c-algo-pcf in the future. + * For now, we never request an IRQ from the PCF8584, and poll it instead. + */ + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/module.h> + +#include <linux/i2c.h> +#include <linux/i2c-algo-pcf.h> + +#include <asm/amigaints.h> +#include <linux/zorro.h> + +#include "../algos/i2c-algo-pcf.h" + + +static int clock = 0x1c; +module_param(clock, int, 0444); + + + +struct icy_i2c { + struct i2c_adapter adapter; + + void __iomem *reg_s0; + void __iomem *reg_s1; +}; + + + +/* + * Functions called by i2c-algo-pcf + */ +static void icy_pcf_setpcf(void *data, int ctl, int val) +{ + struct icy_i2c *i2c = (struct icy_i2c *)data; + + u8 __iomem *address = ctl ? i2c->reg_s1 : i2c->reg_s0; + + z_writeb(val, address); +} + +static int icy_pcf_getpcf(void *data, int ctl) +{ + struct icy_i2c *i2c = (struct icy_i2c *)data; + + u8 __iomem *address = ctl ? i2c->reg_s1 : i2c->reg_s0; + int val = z_readb(address); + + return val; +} + +static int icy_pcf_getown(void *data) +{ + return 0x55; +} + +static int icy_pcf_getclock(void *data) +{ + return clock; +} + +static void icy_pcf_waitforpin(void *data) +{ + udelay(100); +} + + + +/* + * Main i2c-icy part + */ +static int icy_probe(struct zorro_dev *z, + const struct zorro_device_id *ent) +{ + struct icy_i2c *i2c; + struct i2c_algo_pcf_data *algo_data; + + + i2c = devm_kzalloc(&z->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + algo_data = devm_kzalloc(&z->dev, sizeof(*algo_data), GFP_KERNEL); + if (!algo_data) + return -ENOMEM; + + dev_set_drvdata(&z->dev, i2c); + i2c->adapter.dev.parent = &z->dev; + i2c->adapter.owner = THIS_MODULE; + i2c->adapter.class = I2C_CLASS_DEPRECATED; + /* i2c->adapter.algo assigned by i2c_pcf_add_bus() */ + i2c->adapter.algo_data = algo_data; + strlcpy(i2c->adapter.name, "ICY I2C Zorro adapter", + sizeof(i2c->adapter.name)); + + if (!devm_request_mem_region(&z->dev, + z->resource.start, + 4, i2c->adapter.name)) + return -ENXIO; + + /* Driver private data */ + i2c->reg_s0 = ZTWO_VADDR(z->resource.start); + i2c->reg_s1 = ZTWO_VADDR(z->resource.start + 2); + + algo_data->data = (void *)i2c; + algo_data->setpcf = icy_pcf_setpcf; + algo_data->getpcf = icy_pcf_getpcf; + algo_data->getown = icy_pcf_getown; + algo_data->getclock = icy_pcf_getclock; + algo_data->waitforpin = icy_pcf_waitforpin; + + if (i2c_pcf_add_bus(&i2c->adapter)) { + dev_err(&z->dev, "i2c_pcf_add_bus() failed\n"); + return -ENXIO; + } + + dev_info(&z->dev, "ICY I2C controller at %#x, IRQ not implemented\n", + z->resource.start); + + return 0; +} + +static void icy_remove(struct zorro_dev *z) +{ + struct icy_i2c *i2c = dev_get_drvdata(&z->dev); + + i2c_del_adapter(&i2c->adapter); +} + + + +static const struct zorro_device_id icy_zorro_tbl[] = { + { ZORRO_ID(VMC, 15, 0), }, + { 0 } +}; + +MODULE_DEVICE_TABLE(zorro, icy_zorro_tbl); + +static struct zorro_driver icy_driver = { + .name = "i2c-icy", + .id_table = icy_zorro_tbl, + .probe = icy_probe, + .remove = icy_remove, +}; + +module_driver(icy_driver, + zorro_register_driver, + zorro_unregister_driver); + + +MODULE_AUTHOR("Max Staudt <max@enpas.org>"); +MODULE_DESCRIPTION("I2C bus via PCF8584 on ICY Zorro card"); +MODULE_LICENSE("GPL");
This is the i2c-icy driver for the ICY board for Amiga computers. It connects a PCF8584 I2C controller to the Zorro bus, providing I2C connectivity. The original documentation can be found on Aminet: https://aminet.net/package/docs/hard/icy IRQ support is currently not implemented, as i2c-algo-pcf is built for the ISA bus and a straight implementation of the same stack locks up a Zorro machine. v2: Matched function names to callbacks from i2c-algo-pcf Used z_readb()/z_writeb() Removed BROKEN_ON_SMP in Kconfig Moved LTC2990 to a separate commit Signed-off-by: Max Staudt <max@enpas.org> --- MAINTAINERS | 6 ++ drivers/i2c/busses/Kconfig | 11 +++ drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-icy.c | 189 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+) create mode 100644 drivers/i2c/busses/i2c-icy.c