Re: [PATCH 16/16] drivers/fsi: Add GPIO based FSI master
On Thu, Dec 8, 2016 at 10:12 PM, Jeremy Kerr wrote: > Hi Chris, > >> +static ssize_t store_scan(struct device *dev, >> + struct device_attribute *attr, >> + const char *buf, >> + size_t count) >> +{ >> + struct fsi_master_gpio *master = dev_get_drvdata(dev); >> + >> + fsi_master_gpio_init(master); >> + >> + /* clear out any old scan data if present */ >> + fsi_master_unregister(&master->master); >> + fsi_master_register(&master->master); >> + >> + return count; >> +} >> + >> +static DEVICE_ATTR(scan, 0200, NULL, store_scan); > > I think it would make more sense to have the scan attribute populated by > the fsi core; we want this on all masters, not just GPIO. > Hi Jeremy, Sure, will move that to the core. > Currently, the only GPIO-master-specific functionality here is the > fsi_master_gpio_init() - but isn't this something that we can do at > probe time instead? > Yes that can be done at probe time. Will change. >> +static int fsi_master_gpio_probe(struct platform_device *pdev) >> +{ >> + struct fsi_master_gpio *master; >> + struct gpio_desc *gpio; >> + >> + master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); >> + if (!master) >> + return -ENOMEM; > > We should be populating master->dev.parent, see > > https://github.com/jk-ozlabs/linux/commit/5225d6c47 > > Will make the change. >> + /* Optional pins */ >> + >> + gpio = devm_gpiod_get(&pdev->dev, "trans", 0); >> + if (IS_ERR(gpio)) >> + dev_dbg(&pdev->dev, "probe: failed to get trans pin\n"); >> + else >> + master->gpio_trans = gpio; > > I found devm_gpiod_get_optional(), which might make this a little > neater. Will make this change. Thanks, Chris > > Cheers, > > > Jeremy
Re: [PATCH 16/16] drivers/fsi: Add GPIO based FSI master
Hi Chris, > +static ssize_t store_scan(struct device *dev, > + struct device_attribute *attr, > + const char *buf, > + size_t count) > +{ > + struct fsi_master_gpio *master = dev_get_drvdata(dev); > + > + fsi_master_gpio_init(master); > + > + /* clear out any old scan data if present */ > + fsi_master_unregister(&master->master); > + fsi_master_register(&master->master); > + > + return count; > +} > + > +static DEVICE_ATTR(scan, 0200, NULL, store_scan); I think it would make more sense to have the scan attribute populated by the fsi core; we want this on all masters, not just GPIO. Currently, the only GPIO-master-specific functionality here is the fsi_master_gpio_init() - but isn't this something that we can do at probe time instead? > +static int fsi_master_gpio_probe(struct platform_device *pdev) > +{ > + struct fsi_master_gpio *master; > + struct gpio_desc *gpio; > + > + master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); > + if (!master) > + return -ENOMEM; We should be populating master->dev.parent, see https://github.com/jk-ozlabs/linux/commit/5225d6c47 > + /* Optional pins */ > + > + gpio = devm_gpiod_get(&pdev->dev, "trans", 0); > + if (IS_ERR(gpio)) > + dev_dbg(&pdev->dev, "probe: failed to get trans pin\n"); > + else > + master->gpio_trans = gpio; I found devm_gpiod_get_optional(), which might make this a little neater. Cheers, Jeremy
[PATCH 16/16] drivers/fsi: Add GPIO based FSI master
From: Chris Bostic Implement a FSI master using GPIO. Will generate FSI protocol for read and write commands to particular addresses. Sends master command and waits for and decodes a slave response. Includes Jeremy Kerr's original GPIO master base commit. Signed-off-by: Jeremy Kerr Signed-off-by: Chris Bostic --- drivers/fsi/Kconfig | 7 + drivers/fsi/Makefile | 1 + drivers/fsi/fsi-master-gpio.c | 552 ++ 3 files changed, 560 insertions(+) create mode 100644 drivers/fsi/fsi-master-gpio.c diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig index f065dbe..9530459 100644 --- a/drivers/fsi/Kconfig +++ b/drivers/fsi/Kconfig @@ -17,6 +17,13 @@ config FSI_MASTER_FAKE depends on FSI ---help--- This option enables a fake FSI master driver for debugging. + +config FSI_MASTER_GPIO + tristate "GPIO-based FSI master" + depends on FSI && GPIOLIB + ---help--- + This option enables a FSI master driver using GPIO lines. + endif endmenu diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile index 847c00c..2021ce5 100644 --- a/drivers/fsi/Makefile +++ b/drivers/fsi/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_FSI) += fsi-core.o obj-$(CONFIG_FSI_MASTER_FAKE) += fsi-master-fake.o +obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o diff --git a/drivers/fsi/fsi-master-gpio.c b/drivers/fsi/fsi-master-gpio.c new file mode 100644 index 000..79cb0b1 --- /dev/null +++ b/drivers/fsi/fsi-master-gpio.c @@ -0,0 +1,552 @@ +/* + * A FSI master controller, using a simple GPIO bit-banging interface + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fsi-master.h" + +#defineFSI_GPIO_STD_DLY1 /* Standard pin delay in nS */ +#defineFSI_ECHO_DELAY_CLOCKS 16 /* Number clocks for echo delay */ +#defineFSI_PRE_BREAK_CLOCKS50 /* Number clocks to prep for break */ +#defineFSI_BREAK_CLOCKS256 /* Number of clocks to issue break */ +#defineFSI_POST_BREAK_CLOCKS 16000 /* Number clocks to set up cfam */ +#defineFSI_INIT_CLOCKS 5000/* Clock out any old data */ +#defineFSI_GPIO_STD_DELAY 10 /* Standard GPIO delay in nS */ + /* todo: adjust down as low as */ + /* possible or eliminate */ +#defineFSI_GPIO_CMD_DPOLL 0x002AULL +#defineFSI_GPIO_CMD_DPOLL_SIZE 9 +#defineFSI_GPIO_DPOLL_CLOCKS 100 /* < 21 will cause slave to hang */ +#defineFSI_GPIO_CMD_DEFAULT0x2000ULL +#defineFSI_GPIO_CMD_WRITE 0 +#defineFSI_GPIO_CMD_READ 0x0400ULL +#defineFSI_GPIO_CMD_SLAVE_MASK 0xC000ULL +#defineFSI_GPIO_CMD_ADDR_SHIFT 37 +#defineFSI_GPIO_CMD_ADDR_MASK 0x001F +#defineFSI_GPIO_CMD_SLV_SHIFT 62 +#defineFSI_GPIO_CMD_SIZE_160x0010ULL +#defineFSI_GPIO_CMD_SIZE_320x0030ULL +#defineFSI_GPIO_CMD_DT32_SHIFT 4 +#defineFSI_GPIO_CMD_DT16_SHIFT 20 +#defineFSI_GPIO_CMD_DT8_SHIFT 28 +#defineFSI_GPIO_CMD_DFLT_LEN 28 +#defineFSI_GPIO_CMD_CRC_SHIFT 60 + +/* Bus errors */ +#defineFSI_GPIO_ERR_BUSY 1 /* Slave stuck in busy state */ +#defineFSI_GPIO_RESP_ERRA 2 /* Any (misc) Error */ +#defineFSI_GPIO_RESP_ERRC 3 /* Slave reports master CRC error */ +#defineFSI_GPIO_MTOE 4 /* Master time out error */ +#defineFSI_GPIO_CRC_INVAL 5 /* Master reports slave CRC error */ + +/* Normal slave responses */ +#defineFSI_GPIO_RESP_BUSY 1 +#defineFSI_GPIO_RESP_ACK 0 +#defineFSI_GPIO_RESP_ACKD 4 + +#defineFSI_GPIO_MAX_BUSY 100 +#defineFSI_GPIO_MTOE_COUNT 1000 +#defineFSI_GPIO_DRAIN_BITS 20 +#defineFSI_GPIO_CRC_SIZE 4 +#defineFSI_GPIO_MSG_ID_SIZE2 +#defineFSI_GPIO_MSG_RESPID_SIZE2 +#defineFSI_GPIO_PRIME_SLAVE_CLOCKS 100 + +static DEFINE_SPINLOCK(fsi_gpio_cmd_lock); /* lock around fsi commands */ + +struct fsi_master_gpio { + struct fsi_master master; + struct gpio_desc*gpio_clk; + struct gpio_desc*gpio_data; + struct gpio_desc*gpio_trans;/* Voltage translator */ + struct gpio_desc*gpio_enable; /* FSI enable */ + struct gpio_desc*gpio_mux; /* Mux control */ +}; + +#define to_fsi_master_gpio(m) container_of(m, struct fsi_master_gpio, master) + +struct fsi_gpio_msg { + uint64_tmsg; + uint8_t bits; +}; + +static void clock_toggle(struct fsi_master_gpio *master, int count) +{ + int i; + + for (i = 0; i < count; i