serial: 8250_dw: Add DMA support for non-ACPI platforms
Subsystems (18)
Ray Jui
maintainerRe: [PATCH 2/4] i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Varka BhadramQuoted 201 lines · Varka Bhadram
Quoted 186 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- drivers/i2c/busses/Kconfig | 9 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 503 ++++++++++++++++++++++++++++++++++++ 3 files changed, 513 insertions(+)create mode 100644
drivers/i2c/busses/i2c-bcm-iproc.cdrivers/i2c/busses/Kconfig +9
-0@@ -372,6 +372,15 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC + help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILEdrivers/i2c/busses/Makefile +1
-0@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.odrivers/i2c/busses/i2c-bcm-iproc.c new file +102
-0@@ -0,0 +1,503 @@ +/* +* Copyright (C) 2014 Broadcom Corporation +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/delay.h> + +#define CFG_OFFSET 0x00 +#define CFG_RESET_SHIFT 31 +#define CFG_EN_SHIFT 30 +#define CFG_M_RETRY_CNT_SHIFT 16 +#define CFG_M_RETRY_CNT_MASK 0x0f + +#define TIM_CFG_OFFSET 0x04 +#define TIME_CFG_MODE_400_SHIFT 31 + +#define M_FIFO_CTRL_OFFSET 0x0c +#define M_FIFO_RX_FLUSH_SHIFT 31 +#define M_FIFO_TX_FLUSH_SHIFT 30 +#define M_FIFO_RX_CNT_SHIFT 16 +#define M_FIFO_RX_CNT_MASK 0x7f +#define M_FIFO_RX_THLD_SHIFT 8 +#define M_FIFO_RX_THLD_MASK 0x3f + +#define M_CMD_OFFSET 0x30 +#define M_CMD_START_BUSY_SHIFT 31 +#define M_CMD_STATUS_SHIFT 25 +#define M_CMD_STATUS_MASK 0x07 +#define M_CMD_STATUS_SUCCESS 0x0 +#define M_CMD_STATUS_LOST_ARB 0x1 +#define M_CMD_STATUS_NACK_ADDR 0x2 +#define M_CMD_STATUS_NACK_DATA 0x3 +#define M_CMD_STATUS_TIMEOUT 0x4 +#define M_CMD_PROTOCOL_SHIFT 9 +#define M_CMD_PROTOCOL_MASK 0xf +#define M_CMD_PROTOCOL_BLK_WR 0x7 +#define M_CMD_PROTOCOL_BLK_RD 0x8 +#define M_CMD_PEC_SHIFT 8 +#define M_CMD_RD_CNT_SHIFT 0 +#define M_CMD_RD_CNT_MASK 0xff + +#define IE_OFFSET 0x38 +#define IE_M_RX_FIFO_FULL_SHIFT 31 +#define IE_M_RX_THLD_SHIFT 30 +#define IE_M_START_BUSY_SHIFT 28 + +#define IS_OFFSET 0x3c +#define IS_M_RX_FIFO_FULL_SHIFT 31 +#define IS_M_RX_THLD_SHIFT 30 +#define IS_M_START_BUSY_SHIFT 28 + +#define M_TX_OFFSET 0x40 +#define M_TX_WR_STATUS_SHIFT 31 +#define M_TX_DATA_SHIFT 0 +#define M_TX_DATA_MASK 0xff + +#define M_RX_OFFSET 0x44 +#define M_RX_STATUS_SHIFT 30 +#define M_RX_STATUS_MASK 0x03 +#define M_RX_PEC_ERR_SHIFT 29 +#define M_RX_DATA_SHIFT 0 +#define M_RX_DATA_MASK 0xff + +#define I2C_TIMEOUT_MESC 100 +#define M_TX_RX_FIFO_SIZE 64 + +enum bus_speed_index { +I2C_SPD_100K =0 , +I2C_SPD_400K , +}; + +struct bcm_iproc_i2c_dev { +struct device *device; + +void __iomem *base; +struct i2c_msg *msg; + +struct i2c_adapter adapter; + +struct completion done; +}; + +/* +* Can be expanded in the future if more interrupt status bits are utilized
+ */drivers/i2c/busses/i2c-bcm-iproc.c new file +21
-0+#define ISR_MASK (1 << IS_M_START_BUSY_SHIFT) + +static irqreturn_t bcm_iproc_i2c_isr (int irq,void *data) +{ +struct bcm_iproc_i2c_dev *dev = data; +u32 status =readl (dev->base +IS_OFFSET ); + + status &=ISR_MASK ; + +if (!status) +return IRQ_NONE ; + +writel (status, dev->base +IS_OFFSET ); +complete_all (&dev->done); + +return IRQ_HANDLED ; +} + +static int __wait_for_bus_idle (struct bcm_iproc_i2c_dev *dev) +{ + unsigned long timeout = jiffies +
msecs_to_jiffies(I2C_TIMEOUT_MESC);drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+ +while (readl (dev->base +M_CMD_OFFSET ) & + (1 <<M_CMD_START_BUSY_SHIFT )) { +if (time_after (jiffies, timeout)) { +dev_err (dev->device,"wait for bus idle timeout\n" );drivers/i2c/busses/i2c-bcm-iproc.c line 139
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+return -ETIMEDOUT ; + } + } + +return 0 ; +} + +static int bcm_iproc_i2c_format_addr (struct bcm_iproc_i2c_dev *dev, +struct i2c_msg *msg,u8 *addr) +{Match open parenthesis..
Quoted 4 lines
static int bcm_iproc_i2c_format_addr(struct
bcm_iproc_i2c_dev*dev,
structi2c_msg*msg, u8 *addr)
Okay I can make this change.
Quoted 46 lines
Quoted 46 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +46
-0+ +if (msg->flags &I2C_M_TEN ) { +dev_err (dev->device,"no support for 10-bit address\n" ); +return -EINVAL ; + } + + *addr = (msg->addr <<1 ) &0xfe ; + +if (msg->flags &I2C_M_RD ) + *addr |=1 ; + +return 0 ; +} + +static int bcm_iproc_i2c_check_status (struct bcm_iproc_i2c_dev *dev) +{ +u32 val; + + val =readl (dev->base +M_CMD_OFFSET ); + val = (val >>M_CMD_STATUS_SHIFT ) &M_CMD_STATUS_MASK ; + +switch (val) { +case M_CMD_STATUS_SUCCESS : +return 0 ; + +case M_CMD_STATUS_LOST_ARB : +dev_err (dev->device,"lost bus arbitration\n" ); +return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_ADDR : +dev_err (dev->device,"NAK addr:0x%02x\n" , dev->msg->addr); +return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_DATA : +dev_err (dev->device,"NAK data\n" ); +return -EREMOTEIO ; + +case M_CMD_STATUS_TIMEOUT : +dev_err (dev->device,"bus timeout\n" ); +return -ETIMEDOUT ; + +default : +dev_err (dev->device,"unknown error code=%d\n" , val); +return -EREMOTEIO ; + } +
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 191
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+return -EREMOTEIO ; +} + +static int bcm_iproc_i2c_xfer_single_msg (struct bcm_iproc_i2c_dev *dev, +struct i2c_msg *msg) +{dto...
One more indent? Sure.
Quoted 234 lines
Quoted 234 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +48
-0+int ret, i; +u8 addr; +u32 val; +unsigned long time_left =msecs_to_jiffies (I2C_TIMEOUT_MESC ); + +if (msg->len <1 || msg->len >M_TX_RX_FIFO_SIZE -1 ) { +dev_err (dev->device, +"supported data length is 1 - %u bytes\n" , +M_TX_RX_FIFO_SIZE -1 ); +return -EINVAL ; + } + + dev->msg = msg; + ret =__wait_for_bus_idle (dev); +if (ret) +return ret; + + ret =bcm_iproc_i2c_format_addr (dev, msg, &addr); +if (ret) +return ret; + +/* load slave address into the TX FIFO */ +writel (addr, dev->base +M_TX_OFFSET ); + +/* for a write transaction, load data into the TX FIFO */ +if (!(msg->flags &I2C_M_RD )) { +for (i =0 ; i < msg->len; i++) { + val = msg->buf[i]; + +/* mark the last byte */ +if (i == msg->len -1 ) + val |=1 <<M_TX_WR_STATUS_SHIFT ; + +writel (val, dev->base +M_TX_OFFSET ); + } + } + +/* mark as incomplete before starting the transaction */ +reinit_completion (&dev->done); + +/* +* Enable the "start busy" interrupt, which will be triggered after +* the transaction is done +*/ +writel (1 <<IE_M_START_BUSY_SHIFT , dev->base +IE_OFFSET ); + +/* +* Now we can activate the transfer. For a read operation, specify the
drivers/i2c/busses/i2c-bcm-iproc.c new file +90
-0+* number of bytes to read +*/ + val =1 <<M_CMD_START_BUSY_SHIFT ; +if (msg->flags &I2C_M_RD ) { + val |= (M_CMD_PROTOCOL_BLK_RD <<M_CMD_PROTOCOL_SHIFT ) | + (msg->len <<M_CMD_RD_CNT_SHIFT ); + }else { + val |= (M_CMD_PROTOCOL_BLK_WR <<M_CMD_PROTOCOL_SHIFT ); + } +writel (val, dev->base +M_CMD_OFFSET ); + + time_left =wait_for_completion_timeout (&dev->done, time_left); + +/* disable all interrupts */ +writel (0 , dev->base +IE_OFFSET ); + +if (!time_left) { +dev_err (dev->device,"transaction times out\n" ); + +/* flush FIFOs */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | + (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, dev->base +M_FIFO_CTRL_OFFSET ); +return -EREMOTEIO ; + } + + ret =bcm_iproc_i2c_check_status (dev); +if (ret) { +/* flush both TX/RX FIFOs */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | + (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, dev->base +M_FIFO_CTRL_OFFSET ); +return ret; + } + +/* +* For a read operation, we now need to load the data from FIFO +* into the memory buffer +*/ +if (msg->flags &I2C_M_RD ) { +for (i =0 ; i < msg->len; i++) { + msg->buf[i] = (readl (dev->base +M_RX_OFFSET ) >> +M_RX_DATA_SHIFT ) &M_RX_DATA_MASK ; + } + } + +dev_dbg (dev->device,"xfer %c, addr=0x%02x, len=%d\n" , + (msg->flags &I2C_M_RD ) ?'R' :'W' , msg->addr, + msg->len); +dev_dbg (dev->device,"**** data start ****\n" ); +for (i =0 ; i < msg->len; i++) +dev_dbg (dev->device,"0x%02x " , msg->buf[i]); +dev_dbg (dev->device,"**** data end ****\n" ); + +return 0 ; +} + +static int bcm_iproc_i2c_xfer (struct i2c_adapter *adapter, +struct i2c_msg msgs[],int num) +{ +struct bcm_iproc_i2c_dev *dev =i2c_get_adapdata (adapter); +int ret, i; + +/* go through all messages */ +for (i =0 ; i < num; i++) { + ret =bcm_iproc_i2c_xfer_single_msg (dev, &msgs[i]); +if (ret) { +dev_err (dev->device,"xfer failed\n" ); +return ret; + } + } + +return num; +} + +static uint32_t bcm_iproc_i2c_functionality (struct i2c_adapter *adap) +{ +return I2C_FUNC_I2C |I2C_FUNC_SMBUS_EMUL ; +} + +static const struct i2c_algorithm bcm_iproc_algo = { + .master_xfer = bcm_iproc_i2c_xfer, + .functionality = bcm_iproc_i2c_functionality, +}; + +static int bcm_iproc_i2c_cfg_speed (struct bcm_iproc_i2c_dev *dev) +{ +unsigned int bus_speed, speed_bit; +u32 val; + int ret = of_property_read_u32(dev->device->of_node,"clock-frequency",
drivers/i2c/busses/i2c-bcm-iproc.c new file +94
-0+ &bus_speed); +if (ret <0 ) { +dev_err (dev->device,"missing clock-frequency property\n" ); +return -ENODEV ; + } + +switch (bus_speed) { +case 100000 : + speed_bit =0 ; +break ; +case 400000 : + speed_bit =1 ; +break ; +default : +dev_err (dev->device,"%d Hz bus speed not supported\n" , + bus_speed); +dev_err (dev->device,"valid speeds are 100khz and 400khz\n" ); +return -EINVAL ; + } + + val =readl (dev->base +TIM_CFG_OFFSET ); + val &= ~(1 <<TIME_CFG_MODE_400_SHIFT ); + val |= speed_bit <<TIME_CFG_MODE_400_SHIFT ; +writel (val, dev->base +TIM_CFG_OFFSET ); + +dev_info (dev->device,"bus set to %u Hz\n" , bus_speed); + +return 0 ; +} + +static int bcm_iproc_i2c_init (struct bcm_iproc_i2c_dev *dev) +{ +u32 val; + +/* put controller in reset */ + val =readl (dev->base +CFG_OFFSET ); + val |=1 <<CFG_RESET_SHIFT ; + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, dev->base +CFG_OFFSET ); + +/* wait 100 usec per spec */ +udelay (100 ); + +/* bring controller out of reset */ + val =readl (dev->base +CFG_OFFSET ); + val &= ~(1 <<CFG_RESET_SHIFT ); +writel (val, dev->base +CFG_OFFSET ); + +/* flush TX/RX FIFOs and set RX FIFO threshold to zero */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, dev->base +M_FIFO_CTRL_OFFSET ); + +/* disable all interrupts */ + val =0 ; +writel (val, dev->base +IE_OFFSET ); + +/* clear all pending interrupts */ + val =readl (dev->base +IS_OFFSET ); +writel (val, dev->base +IS_OFFSET ); + +return 0 ; +} + +static void bcm_iproc_i2c_enable (struct bcm_iproc_i2c_dev *dev) +{ +u32 val; + + val =readl (dev->base +CFG_OFFSET ); + val |=1 <<CFG_EN_SHIFT ; +writel (val, dev->base +CFG_OFFSET ); +} + +static void bcm_iproc_i2c_disable (struct bcm_iproc_i2c_dev *dev) +{ +u32 val; + + val =readl (dev->base +CFG_OFFSET ); + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, dev->base +CFG_OFFSET ); +} + +static int bcm_iproc_i2c_probe (struct platform_device *pdev) +{ +int irq, ret =0 ; +struct bcm_iproc_i2c_dev *dev; +struct i2c_adapter *adap; +struct resource *res; + + dev =devm_kzalloc (&pdev->dev,sizeof (*dev),GFP_KERNEL ); +if (!dev) +return -ENOMEM ; + +platform_set_drvdata (pdev, dev); + dev->device = &pdev->dev;
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 428
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+init_completion (&dev->done); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (!res) +return -ENODEV ;We can remove this resource check. This checking will happen with
devm_ioremap_resource()
Don't you need to obtain a valid resource and pass it into devm_ioremap_resource? Without 'res' being assigned a valid resource, devm_ioremap_resource will reject with "invalid resource".
Quoted 60 lines
Quoted 60 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +30
-0+ dev->base =devm_ioremap_resource (dev->device, res); +if (IS_ERR (dev->base)) +return -ENOMEM ; + + ret =bcm_iproc_i2c_init (dev); +if (ret) +return ret; + + ret =bcm_iproc_i2c_cfg_speed (dev); +if (ret) +return ret; + + irq =platform_get_irq (pdev,0 ); +if (irq <0 ) { +dev_err (dev->device,"no irq resource\n" ); +return irq; + } + + ret =devm_request_irq (&pdev->dev, irq, bcm_iproc_i2c_isr, +IRQF_SHARED , pdev->name, dev); +if (ret) { +dev_err (dev->device,"unable to request irq %i\n" , irq); +return ret; + } + +bcm_iproc_i2c_enable (dev); + + adap = &dev->adapter; +i2c_set_adapdata (adap, dev); + strlcpy(adap->name, "Broadcom iProc I2C adapter",
sizeof(adap->name));drivers/i2c/busses/i2c-bcm-iproc.c new file +29
-0+ adap->algo = &bcm_iproc_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + + ret =i2c_add_adapter (adap); +if (ret) { +dev_err (dev->device,"failed to add adapter\n" ); +return ret; + } + +dev_info (dev->device,"device registered successfully\n" ); + +return 0 ; +} + +static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *dev =platform_get_drvdata (pdev); + +i2c_del_adapter (&dev->adapter); +bcm_iproc_i2c_disable (dev); + +return 0 ; +} + +static const struct of_device_id bcm_iproc_i2c_of_match[] = { + {.compatible ="brcm,iproc-i2c" ,}, + {}, +};
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 493
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+MODULE_DEVICE_TABLE (of, bcm_iproc_i2c_of_match); + +static struct platform_driver bcm_iproc_i2c_driver = { + .driver = { + .name ="bcm-iproc-i2c" , + .owner =THIS_MODULE ,No need to update this field. Its updated by
module_platform_driver().
Okay will get rid of .owner = THIS_MODULES,
Quoted 11 lines
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ .of_match_table = bcm_iproc_i2c_of_match, + }, + .probe = bcm_iproc_i2c_probe, + .remove = bcm_iproc_i2c_remove, +}; +module_platform_driver (bcm_iproc_i2c_driver); + +MODULE_AUTHOR ("Ray Jui <[email protected]>" ); +MODULE_DESCRIPTION ("Broadcom iProc I2C Driver" ); +MODULE_LICENSE ("GPL v2" );
Re: [PATCH 2/4] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 31 lines · Ray Jui
Quoted 20 lines · Varka Bhadram
Quoted 17 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- drivers/i2c/busses/Kconfig | 9 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 503 ++++++++++++++++++++++++++++++++++++ 3 files changed, 513 insertions(+)create mode 100644
drivers/i2c/busses/i2c-bcm-iproc.cQuoted 1 line
Quoted 1 line
(...)
+static int bcm_iproc_i2c_xfer_single_msg(struct
bcm_iproc_i2c_dev*dev,Quoted 4 lines
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +2
-0+ struct i2c_msg *msg) +{
Quoted 5 lines
Quoted 3 lines
dto...
One more indent? Sure.
Yes...
static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *dev,
struct i2c_msg *msg)
Quoted 245 lines
+ int ret, i;
Quoted 243 lines
Quoted 229 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +47
-0+u8 addr; +u32 val; +unsigned long time_left =msecs_to_jiffies (I2C_TIMEOUT_MESC ); + +if (msg->len <1 || msg->len >M_TX_RX_FIFO_SIZE -1 ) { +dev_err (dev->device, +"supported data length is 1 - %u bytes\n" , +M_TX_RX_FIFO_SIZE -1 ); +return -EINVAL ; + } + + dev->msg = msg; + ret =__wait_for_bus_idle (dev); +if (ret) +return ret; + + ret =bcm_iproc_i2c_format_addr (dev, msg, &addr); +if (ret) +return ret; + +/* load slave address into the TX FIFO */ +writel (addr, dev->base +M_TX_OFFSET ); + +/* for a write transaction, load data into the TX FIFO */ +if (!(msg->flags &I2C_M_RD )) { +for (i =0 ; i < msg->len; i++) { + val = msg->buf[i]; + +/* mark the last byte */ +if (i == msg->len -1 ) + val |=1 <<M_TX_WR_STATUS_SHIFT ; + +writel (val, dev->base +M_TX_OFFSET ); + } + } + +/* mark as incomplete before starting the transaction */ +reinit_completion (&dev->done); + +/* +* Enable the "start busy" interrupt, which will be triggered after +* the transaction is done +*/ +writel (1 <<IE_M_START_BUSY_SHIFT , dev->base +IE_OFFSET ); + +/* +* Now we can activate the transfer. For a read operation, specify the
drivers/i2c/busses/i2c-bcm-iproc.c new file +90
-0+* number of bytes to read +*/ + val =1 <<M_CMD_START_BUSY_SHIFT ; +if (msg->flags &I2C_M_RD ) { + val |= (M_CMD_PROTOCOL_BLK_RD <<M_CMD_PROTOCOL_SHIFT ) | + (msg->len <<M_CMD_RD_CNT_SHIFT ); + }else { + val |= (M_CMD_PROTOCOL_BLK_WR <<M_CMD_PROTOCOL_SHIFT ); + } +writel (val, dev->base +M_CMD_OFFSET ); + + time_left =wait_for_completion_timeout (&dev->done, time_left); + +/* disable all interrupts */ +writel (0 , dev->base +IE_OFFSET ); + +if (!time_left) { +dev_err (dev->device,"transaction times out\n" ); + +/* flush FIFOs */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | + (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, dev->base +M_FIFO_CTRL_OFFSET ); +return -EREMOTEIO ; + } + + ret =bcm_iproc_i2c_check_status (dev); +if (ret) { +/* flush both TX/RX FIFOs */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | + (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, dev->base +M_FIFO_CTRL_OFFSET ); +return ret; + } + +/* +* For a read operation, we now need to load the data from FIFO +* into the memory buffer +*/ +if (msg->flags &I2C_M_RD ) { +for (i =0 ; i < msg->len; i++) { + msg->buf[i] = (readl (dev->base +M_RX_OFFSET ) >> +M_RX_DATA_SHIFT ) &M_RX_DATA_MASK ; + } + } + +dev_dbg (dev->device,"xfer %c, addr=0x%02x, len=%d\n" , + (msg->flags &I2C_M_RD ) ?'R' :'W' , msg->addr, + msg->len); +dev_dbg (dev->device,"**** data start ****\n" ); +for (i =0 ; i < msg->len; i++) +dev_dbg (dev->device,"0x%02x " , msg->buf[i]); +dev_dbg (dev->device,"**** data end ****\n" ); + +return 0 ; +} + +static int bcm_iproc_i2c_xfer (struct i2c_adapter *adapter, +struct i2c_msg msgs[],int num) +{ +struct bcm_iproc_i2c_dev *dev =i2c_get_adapdata (adapter); +int ret, i; + +/* go through all messages */ +for (i =0 ; i < num; i++) { + ret =bcm_iproc_i2c_xfer_single_msg (dev, &msgs[i]); +if (ret) { +dev_err (dev->device,"xfer failed\n" ); +return ret; + } + } + +return num; +} + +static uint32_t bcm_iproc_i2c_functionality (struct i2c_adapter *adap) +{ +return I2C_FUNC_I2C |I2C_FUNC_SMBUS_EMUL ; +} + +static const struct i2c_algorithm bcm_iproc_algo = { + .master_xfer = bcm_iproc_i2c_xfer, + .functionality = bcm_iproc_i2c_functionality, +}; + +static int bcm_iproc_i2c_cfg_speed (struct bcm_iproc_i2c_dev *dev) +{ +unsigned int bus_speed, speed_bit; +u32 val; + int ret = of_property_read_u32(dev->device->of_node,"clock-frequency",
drivers/i2c/busses/i2c-bcm-iproc.c new file +89
-0+ &bus_speed); +if (ret <0 ) { +dev_err (dev->device,"missing clock-frequency property\n" ); +return -ENODEV ; + } + +switch (bus_speed) { +case 100000 : + speed_bit =0 ; +break ; +case 400000 : + speed_bit =1 ; +break ; +default : +dev_err (dev->device,"%d Hz bus speed not supported\n" , + bus_speed); +dev_err (dev->device,"valid speeds are 100khz and 400khz\n" ); +return -EINVAL ; + } + + val =readl (dev->base +TIM_CFG_OFFSET ); + val &= ~(1 <<TIME_CFG_MODE_400_SHIFT ); + val |= speed_bit <<TIME_CFG_MODE_400_SHIFT ; +writel (val, dev->base +TIM_CFG_OFFSET ); + +dev_info (dev->device,"bus set to %u Hz\n" , bus_speed); + +return 0 ; +} + +static int bcm_iproc_i2c_init (struct bcm_iproc_i2c_dev *dev) +{ +u32 val; + +/* put controller in reset */ + val =readl (dev->base +CFG_OFFSET ); + val |=1 <<CFG_RESET_SHIFT ; + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, dev->base +CFG_OFFSET ); + +/* wait 100 usec per spec */ +udelay (100 ); + +/* bring controller out of reset */ + val =readl (dev->base +CFG_OFFSET ); + val &= ~(1 <<CFG_RESET_SHIFT ); +writel (val, dev->base +CFG_OFFSET ); + +/* flush TX/RX FIFOs and set RX FIFO threshold to zero */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, dev->base +M_FIFO_CTRL_OFFSET ); + +/* disable all interrupts */ + val =0 ; +writel (val, dev->base +IE_OFFSET ); + +/* clear all pending interrupts */ + val =readl (dev->base +IS_OFFSET ); +writel (val, dev->base +IS_OFFSET ); + +return 0 ; +} + +static void bcm_iproc_i2c_enable (struct bcm_iproc_i2c_dev *dev) +{ +u32 val; + + val =readl (dev->base +CFG_OFFSET ); + val |=1 <<CFG_EN_SHIFT ; +writel (val, dev->base +CFG_OFFSET ); +} + +static void bcm_iproc_i2c_disable (struct bcm_iproc_i2c_dev *dev) +{ +u32 val; + + val =readl (dev->base +CFG_OFFSET ); + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, dev->base +CFG_OFFSET ); +} + +static int bcm_iproc_i2c_probe (struct platform_device *pdev) +{ +int irq, ret =0 ; +struct bcm_iproc_i2c_dev *dev; +struct i2c_adapter *adap; +struct resource *res; + + dev =devm_kzalloc (&pdev->dev,sizeof (*dev),GFP_KERNEL );drivers/i2c/busses/i2c-bcm-iproc.c line 428
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+if (!dev) +return -ENOMEM ; + +platform_set_drvdata (pdev, dev); + dev->device = &pdev->dev; +init_completion (&dev->done); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (!res) +return -ENODEV ;We can remove this resource check. This checking will happen with
devm_ioremap_resource()
Quoted 5 lines
Quoted 1 line
Don't you need to obtain a valid resource and pass it into
devm_ioremap_resource? Without 'res' being assigned a valid resource,devm_ioremap_resourcewill reject with "invalid resource".
platform_get_resource()will return a resource, checking on this
resource is happening at
http://lxr.free-electrons.com/source/lib/devres.c#L115. So no need to check it explicitly.
If you check here it will be duplication of check with resource. Two times we are checking on
the resource. No point of doing like that.
Thanks.
Re: [PATCH 2/4] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 60 lines · Varka Bhadram
Quoted 24 lines · Ray Jui
Quoted 20 lines · Varka Bhadram
Quoted 17 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- drivers/i2c/busses/Kconfig | 9 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 503 ++++++++++++++++++++++++++++++++++++ 3 files changed, 513 insertions(+)create mode 100644
drivers/i2c/busses/i2c-bcm-iproc.cQuoted 1 line
Quoted 1 line
Quoted 1 line
(...)
+static int
bcm_iproc_i2c_probe(struct platform_device *pdev)Quoted 22 lines
Quoted 22 lines
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+{ +int irq, ret =0 ; +struct bcm_iproc_i2c_dev *dev; +struct i2c_adapter *adap; +struct resource *res; + + dev =devm_kzalloc (&pdev->dev,sizeof (*dev),GFP_KERNEL );drivers/i2c/busses/i2c-bcm-iproc.c line 428
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+if (!dev) +return -ENOMEM ; + +platform_set_drvdata (pdev, dev); + dev->device = &pdev->dev; +init_completion (&dev->done); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (!res) +return -ENODEV ;We can remove this resource check. This checking will happen with
devm_ioremap_resource()Quoted 5 lines
Quoted 1 line
Don't you need to obtain a valid resource and pass it into
devm_ioremap_resource? Without 'res' being assigned a valid resource,devm_ioremap_resourcewill reject with "invalid resource".
platform_get_resource()will return a resource, checking on thisresource is happening at
http://lxr.free-electrons.com/source/lib/devres.c#L115. So no need to check it explicitly.
Quoted 6 lines
If you check here it will be duplication of check with resource. Two times we are checking on
the resource. No point of doing like that.Thanks.
See this: http://lxr.free-electrons.com/source/lib/devres.c#L102
Signature · 2 lines
Thanks and Regards, Varka Bhadram.
Ray Jui
maintainerRe: [PATCH 2/4] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 74 lines · Varka Bhadram
On Wed, Dec 10, 2014 at 8:51 AM, Varka Bhadram <[email protected] <mailto:[email protected]>> wrote:
On Wed, Dec 10, 2014 at 7:11 AM, Ray Jui <[email protected] <mailto:[email protected]>> wrote:
On 12/9/2014 5:33 PM, Varka Bhadram wrote:
On Wednesday 10 December 2014 06:24 AM, Ray Jui wrote:
Add initial support to the Broadcom iProc I2C controller found in the
iProc family of SoCs.The iProc I2C controller has separate internal TX and RX FIFOs, each has
a size of 64 bytes. The iProc I2C controller supports two bus speeds
including standard mode (100kHz) and fast mode (400kHz)Signed-off-by Ray Jui <[email protected]<mailto:[email protected]>>
Reviewed-by Scott Branden <[email protected]<mailto:[email protected]>>
---
drivers/i2c/busses/Kconfig| 9 +
drivers/i2c/busses/Makefile| 1 +
drivers/i2c/busses/i2c-bcm-iproc.c| 503
++++++++++++++++++++++++++++++++++++
3 files changed, 513 insertions(+)
create mode 100644drivers/i2c/busses/i2c-bcm-iproc.c(...)
+static int
bcm_iproc_i2c_probe(struct platform_device *pdev)
+{
+ int irq, ret = 0;
+ structbcm_iproc_i2c_dev*dev;
+ structi2c_adapter*adap;
+ struct resource *res;
+
+ dev = devm_kzalloc(&pdev->dev,sizeof(*dev),
GFP_KERNEL);
+ if (!dev)
+ return-ENOMEM;
+
+platform_set_drvdata(pdev, dev);
+dev->device=&pdev->dev;
+init_completion(&dev->done);
+
+ res =platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return-ENODEV;We can remove this resource check. This checking will happen with
devm_ioremap_resource()Don't you need to obtain a valid resource and pass it into
devm_ioremap_resource? Without 'res' being assigned a valid resource,devm_ioremap_resourcewill reject with "invalid resource".
platform_get_resource()will return a resource, checking on this resource is happening at
http://lxr.free-electrons.com/source/lib/devres.c#L115. So no need to check it explicitly.
Quoted 5 lines
If you check here it will be duplication of check with resource. Two times we are checking on
the resource. No point of doing like that.Thanks.
Sorry I misunderstood what you meant. Okay I'll get rid of if (!res) check there. Thanks.
Quoted 7 lines
See this: http://lxr.free-electrons.com/source/lib/devres.c#L102
--
Thanks and Regards,
Varka Bhadram.
Ray Jui
maintainerPATCH 3/4 ARM: mach-bcm: Enable I2C support for iProc
In reply to Ray JuiEnable I2C driver support for Broadcom iProc family of SoCs by selecting I2C_BCM_IPROC
--- arch/arm/mach-bcm/Kconfig | 1 + 1 file changed, 1 insertion(+)
arch/arm/mach-bcm/Kconfig +1 -0
@@ -19,6 +19,7 @@ config ARCH_BCM_IPROC select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select PINCTRL + select I2C_BCM_IPROC help This enables support for systems based on Broadcom IPROC architected SoCs. The IPROC complex contains one or more ARM CPUs along with common
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH 4/4 ARM: dts: add I2C device nodes for Broadcom Cygnus
In reply to Ray JuiAdd I2C device nodes and its properties in bcm-cygnus.dtsi but keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the future
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +20 -0
@@ -70,6 +70,26 @@ }; }; + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c@1800b000 { + compatible = "brcm,iproc-i2c"; + reg = <0x1800b000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + uart0: serial@18020000 { compatible = "snps,dw-apb-uart"; reg = <0x18020000 0x100>;
Signature · 1 line
1.7.9.5
Ray Jui
maintainerv2 cover Add I2C support to Broadcom iProc
In reply to a message not in the archiveThis patchset contains the initial I2C support for Broadcom iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100 kHz) and fast mode (400 kHz)
Changes from v1:
- Fix function argument parenthesis
- Get rid of redundant driver owner field
Ray Jui (4):
i2c: iProc: define Broadcom iProc I2C binding
i2c: iproc: Add Broadcom iProc I2C Driver
ARM: mach-bcm: Enable I2C support for iProc
ARM: dts: add I2C device nodes for Broadcom Cygnus
.../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++ arch/arm/boot/dts/bcm-cygnus.dtsi | 20 + arch/arm/mach-bcm/Kconfig | 1 + drivers/i2c/busses/Kconfig | 9 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 502 ++++++++++++++++++++ 6 files changed, 570 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v2 1/4 i2c: iProc: define Broadcom iProc I2C binding
Document the I2C device tree binding for Broadcom iProc family of SoCs
--- .../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt new file +37 -0
@@ -0,0 +1,37 @@ +Broadcom iProc I2C controller + +Required properties: + +- compatible: + Must be "brcm,iproc-i2c" + +- reg: + Define the base and range of the I/O address space that contain the iProc + I2C controller registers + +- interrupts: + Should contain the I2C interrupt + +- clock-frequency: + This is the I2C bus clock. Need to be either 100000 or 400000 + +- #address-cells: + Always 1 (for I2C addresses) + +- #size-cells: + Always 0 + +Example: + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + + codec: wm8750@1a { + compatible = "wlf,wm8750"; + reg = <0x1a>; + }; + };
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v2 2/4 i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Ray JuiAdd initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
--- drivers/i2c/busses/Kconfig | 9 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 502 ++++++++++++++++++++++++++++++++++++ 3 files changed, 512 insertions(+) create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
drivers/i2c/busses/Kconfig +9 -0
@@ -372,6 +372,15 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC + help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILE
drivers/i2c/busses/Makefile +1 -0
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
drivers/i2c/busses/i2c-bcm-iproc.c new file +502 -0
502 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v2 3/4 ARM: mach-bcm: Enable I2C support for iProc
In reply to Ray JuiEnable I2C driver support for Broadcom iProc family of SoCs by selecting I2C_BCM_IPROC
--- arch/arm/mach-bcm/Kconfig | 1 + 1 file changed, 1 insertion(+)
arch/arm/mach-bcm/Kconfig +1 -0
@@ -19,6 +19,7 @@ config ARCH_BCM_IPROC select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select PINCTRL + select I2C_BCM_IPROC help This enables support for systems based on Broadcom IPROC architected SoCs. The IPROC complex contains one or more ARM CPUs along with common
Signature · 1 line
1.7.9.5
Re: [PATCH v2 3/4] ARM: mach-bcm: Enable I2C support for iProc
Quoted 14 lines · Ray Jui
Enable I2C driver support for Broadcom iProc family of SoCs by selecting
I2C_BCM_IPROCSigned-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- arch/arm/mach-bcm/Kconfig | 1 + 1 file changed, 1 insertion(+)arch/arm/mach-bcm/Kconfig +0
-0
arch/arm/mach-bcm/Kconfig config ARCH_BCM_IPROC · line 22
Quoted 4 lines
arch/arm/mach-bcm/Kconfig +1
-0@@ -19,6 +19,7 @@ config ARCH_BCM_IPROC select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select PINCTRL + select I2C_BCM_IPROC
One way to avoid having to modify mach-bcm/Kconfig would be to have your i2c driver Kconfig do this:
default ARCH_BCM_IPROC
would that work?
Quoted 4 lines
arch/arm/mach-bcm/Kconfig +0
-0help This enables support for systems based on Broadcom IPROC architected SoCs. The IPROC complex contains one or more ARM CPUs along with common
Ray Jui
maintainerRe: [PATCH v2 3/4] ARM: mach-bcm: Enable I2C support for iProc
Quoted 23 lines · Florian Fainelli
Quoted 14 lines · Ray Jui
Enable I2C driver support for Broadcom iProc family of SoCs by selecting
I2C_BCM_IPROCSigned-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- arch/arm/mach-bcm/Kconfig | 1 + 1 file changed, 1 insertion(+)arch/arm/mach-bcm/Kconfig +0
-0arch/arm/mach-bcm/Kconfig config ARCH_BCM_IPROC · line 22
Quoted 4 lines
arch/arm/mach-bcm/Kconfig +1
-0@@ -19,6 +19,7 @@ config ARCH_BCM_IPROC select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select PINCTRL + select I2C_BCM_IPROCOne way to avoid having to modify mach-bcm/Kconfig would be to have your i2c driver
Kconfigdo this:
Quoted 4 lines
default
ARCH_BCM_IPROCwould that work?
Yes. So in which case it is better to select a driver from the architecture specific Kconfig?
Quoted 5 lines
Quoted 4 lines
arch/arm/mach-bcm/Kconfig +0
-0help This enables support for systems based on Broadcom IPROC architected SoCs. The IPROC complex contains one or more ARM CPUs along with common
Re: [PATCH v2 3/4] ARM: mach-bcm: Enable I2C support for iProc
Quoted 26 lines · Ray Jui
Quoted 23 lines · Florian Fainelli
Quoted 14 lines · Ray Jui
Enable I2C driver support for Broadcom iProc family of SoCs by selecting
I2C_BCM_IPROCSigned-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- arch/arm/mach-bcm/Kconfig | 1 + 1 file changed, 1 insertion(+)arch/arm/mach-bcm/Kconfig +0
-0arch/arm/mach-bcm/Kconfig config ARCH_BCM_IPROC · line 22
Quoted 4 lines
arch/arm/mach-bcm/Kconfig +1
-0@@ -19,6 +19,7 @@ config ARCH_BCM_IPROC select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select PINCTRL + select I2C_BCM_IPROCOne way to avoid having to modify mach-bcm/Kconfig would be to have your i2c driver
Kconfigdo this:
Quoted 6 lines
Quoted 4 lines
default
ARCH_BCM_IPROCwould that work?
Yes. So in which case it is better to select a driver from the architecture specific
Kconfig?
I suppose if your driver/subsystem is critical for system boot, like powering a regulator or something that has a critical purpose, a select is probably more appropriate here. If this is just exposing non-critical devices, I would go with a depends on/default at the driver Kconfig level.
This is just how I see things, others would definitively have a different view.
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
arch/arm/mach-bcm/Kconfig +0
-0help This enables support for systems based on Broadcom IPROCarchitected SoCs.
The IPROC complex contains one or more ARM CPUs along with
common
Ray Jui
maintainerRe: [PATCH v2 3/4] ARM: mach-bcm: Enable I2C support for iProc
Quoted 34 lines · Florian Fainelli
Quoted 26 lines · Ray Jui
Quoted 23 lines · Florian Fainelli
Quoted 14 lines · Ray Jui
Enable I2C driver support for Broadcom iProc family of SoCs by selecting
I2C_BCM_IPROCSigned-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- arch/arm/mach-bcm/Kconfig | 1 + 1 file changed, 1 insertion(+)arch/arm/mach-bcm/Kconfig +0
-0arch/arm/mach-bcm/Kconfig config ARCH_BCM_IPROC · line 22
Quoted 4 lines
arch/arm/mach-bcm/Kconfig +1
-0@@ -19,6 +19,7 @@ config ARCH_BCM_IPROC select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select PINCTRL + select I2C_BCM_IPROCOne way to avoid having to modify mach-bcm/Kconfig would be to have your i2c driver
Kconfigdo this:Quoted 6 lines
Quoted 4 lines
default
ARCH_BCM_IPROCwould that work?
Yes. So in which case it is better to select a driver from the architecture specific
Kconfig?
Quoted 8 lines
I suppose if your driver/subsystem is critical for system boot, like powering a regulator or something that has a critical purpose, a select is probably more appropriate here. If this is just exposing non-critical devices, I would go with a depends on/default at the driver
Kconfiglevel.This is just how I see things, others would definitively have a different view.
Okay. Thanks. I default the driver to y in patchset v3 just like some other I2C drivers in the same Kconfig. It already depends on ARCH_BCM_IPROC so it makes sense to set the default to y, i.e., it will be enabled by default for ARCH_BCM_IPROC platforms.
Quoted 9 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
arch/arm/mach-bcm/Kconfig +0
-0help This enables support for systems based on Broadcom IPROCarchitected SoCs.
The IPROC complex contains one or more ARM CPUs along with
common
Ray Jui
maintainerPATCH v2 4/4 ARM: dts: add I2C device nodes for Broadcom Cygnus
In reply to Ray JuiAdd I2C device nodes and its properties in bcm-cygnus.dtsi but keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the future
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +20 -0
@@ -70,6 +70,26 @@ }; }; + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c@1800b000 { + compatible = "brcm,iproc-i2c"; + reg = <0x1800b000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + uart0: serial@18020000 { compatible = "snps,dw-apb-uart"; reg = <0x18020000 0x100>;
Signature · 1 line
1.7.9.5
Ray Jui
maintainerv3 cover Add I2C support to Broadcom iProc
In reply to a message not in the archiveThis patchset contains the initial I2C support for Broadcom iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100 kHz) and fast mode (400 kHz)
Changes from v2:
- Have the I2C driver default to y so it does not need to be selected from ARCH_BCM_IPROC. This also helps to get rid of one patch. The driver still depends on ARCH_BCM_IPROC
- Get rid of redundant check on resource returned by platform_get_resource
Changes from v1:
- Fix function argument parenthesis
- Get rid of redundant driver owner field
Ray Jui (3):
i2c: iProc: define Broadcom iProc I2C binding
i2c: iproc: Add Broadcom iProc I2C Driver
ARM: dts: add I2C device nodes for Broadcom Cygnus
.../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++ arch/arm/boot/dts/bcm-cygnus.dtsi | 20 + drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 500 ++++++++++++++++++++ 5 files changed, 568 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v3 1/3 i2c: iProc: define Broadcom iProc I2C binding
Document the I2C device tree binding for Broadcom iProc family of SoCs
--- .../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt new file +37 -0
@@ -0,0 +1,37 @@ +Broadcom iProc I2C controller + +Required properties: + +- compatible: + Must be "brcm,iproc-i2c" + +- reg: + Define the base and range of the I/O address space that contain the iProc + I2C controller registers + +- interrupts: + Should contain the I2C interrupt + +- clock-frequency: + This is the I2C bus clock. Need to be either 100000 or 400000 + +- #address-cells: + Always 1 (for I2C addresses) + +- #size-cells: + Always 0 + +Example: + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + + codec: wm8750@1a { + compatible = "wlf,wm8750"; + reg = <0x1a>; + }; + };
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v3 2/3 i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Ray JuiAdd initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
--- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 500 ++++++++++++++++++++++++++++++++++++ 3 files changed, 511 insertions(+) create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
drivers/i2c/busses/Kconfig +10 -0
@@ -372,6 +372,16 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC + default y + help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILE
drivers/i2c/busses/Makefile +1 -0
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
drivers/i2c/busses/i2c-bcm-iproc.c new file +500 -0
500 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v3 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Hello,
Quoted 21 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 500 ++++++++++++++++++++++++++++++++++++ 3 files changed, 511 insertions(+) create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.cdrivers/i2c/busses/Kconfig +0
-0
drivers/i2c/busses/Kconfig config I2C_BCM2835 · line 378
Quoted 7 lines
drivers/i2c/busses/Kconfig +4
-0@@ -372,6 +372,16 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC + default y
It would be nice to have the following here to improve compile coverage testing:
depends on ARCH_BCM_IPROC || COMPILE_TEST default ARCH_BCM_IPROC
Quoted 148 lines
drivers/i2c/busses/Kconfig +6
-0+ help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILEdrivers/i2c/busses/Makefile +1
-0@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.odrivers/i2c/busses/i2c-bcm-iproc.c new file +121
-0@@ -0,0 +1,500 @@ +/* +* Copyright (C) 2014 Broadcom Corporation +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/delay.h> + +#define CFG_OFFSET 0x00 +#define CFG_RESET_SHIFT 31 +#define CFG_EN_SHIFT 30 +#define CFG_M_RETRY_CNT_SHIFT 16 +#define CFG_M_RETRY_CNT_MASK 0x0f + +#define TIM_CFG_OFFSET 0x04 +#define TIME_CFG_MODE_400_SHIFT 31 + +#define M_FIFO_CTRL_OFFSET 0x0c +#define M_FIFO_RX_FLUSH_SHIFT 31 +#define M_FIFO_TX_FLUSH_SHIFT 30 +#define M_FIFO_RX_CNT_SHIFT 16 +#define M_FIFO_RX_CNT_MASK 0x7f +#define M_FIFO_RX_THLD_SHIFT 8 +#define M_FIFO_RX_THLD_MASK 0x3f + +#define M_CMD_OFFSET 0x30 +#define M_CMD_START_BUSY_SHIFT 31 +#define M_CMD_STATUS_SHIFT 25 +#define M_CMD_STATUS_MASK 0x07 +#define M_CMD_STATUS_SUCCESS 0x0 +#define M_CMD_STATUS_LOST_ARB 0x1 +#define M_CMD_STATUS_NACK_ADDR 0x2 +#define M_CMD_STATUS_NACK_DATA 0x3 +#define M_CMD_STATUS_TIMEOUT 0x4 +#define M_CMD_PROTOCOL_SHIFT 9 +#define M_CMD_PROTOCOL_MASK 0xf +#define M_CMD_PROTOCOL_BLK_WR 0x7 +#define M_CMD_PROTOCOL_BLK_RD 0x8 +#define M_CMD_PEC_SHIFT 8 +#define M_CMD_RD_CNT_SHIFT 0 +#define M_CMD_RD_CNT_MASK 0xff + +#define IE_OFFSET 0x38 +#define IE_M_RX_FIFO_FULL_SHIFT 31 +#define IE_M_RX_THLD_SHIFT 30 +#define IE_M_START_BUSY_SHIFT 28 + +#define IS_OFFSET 0x3c +#define IS_M_RX_FIFO_FULL_SHIFT 31 +#define IS_M_RX_THLD_SHIFT 30 +#define IS_M_START_BUSY_SHIFT 28 + +#define M_TX_OFFSET 0x40 +#define M_TX_WR_STATUS_SHIFT 31 +#define M_TX_DATA_SHIFT 0 +#define M_TX_DATA_MASK 0xff + +#define M_RX_OFFSET 0x44 +#define M_RX_STATUS_SHIFT 30 +#define M_RX_STATUS_MASK 0x03 +#define M_RX_PEC_ERR_SHIFT 29 +#define M_RX_DATA_SHIFT 0 +#define M_RX_DATA_MASK 0xff + +#define I2C_TIMEOUT_MESC 100 +#define M_TX_RX_FIFO_SIZE 64 + +enum bus_speed_index { +I2C_SPD_100K =0 , +I2C_SPD_400K , +}; + +struct bcm_iproc_i2c_dev { +struct device *device; + +void __iomem *base; +struct i2c_msg *msg; + +struct i2c_adapter adapter; + +struct completion done; +}; + +/* +* Can be expanded in the future if more interrupt status bits are utilized +*/ +#define ISR_MASK (1 << IS_M_START_BUSY_SHIFT) + +static irqreturn_t bcm_iproc_i2c_isr (int irq,void *data) +{ +struct bcm_iproc_i2c_dev *dev = data; +u32 status =readl (dev->base +IS_OFFSET ); + + status &=ISR_MASK ; + +if (!status) +return IRQ_NONE ; + +writel (status, dev->base +IS_OFFSET ); +complete_all (&dev->done); + +return IRQ_HANDLED ; +} +
drivers/i2c/busses/i2c-bcm-iproc.c line 131
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+static int __wait_for_bus_idle (struct bcm_iproc_i2c_dev *dev) +{ +unsigned long timeout = jiffies +msecs_to_jiffies (I2C_TIMEOUT_MESC ); + +while (readl (dev->base +M_CMD_OFFSET ) & + (1 <<M_CMD_START_BUSY_SHIFT )) { +if (time_after (jiffies, timeout)) { +dev_err (dev->device,"wait for bus idle timeout\n" ); +return -ETIMEDOUT ; + }
Add a call to cpu_relax here. Do you really need a tight loop here?
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+ } + +return 0 ; +} +
drivers/i2c/busses/i2c-bcm-iproc.c line 146
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+static int bcm_iproc_i2c_format_addr (struct bcm_iproc_i2c_dev *dev, +struct i2c_msg *msg,u8 *addr) +{ + +if (msg->flags &I2C_M_TEN ) { +dev_err (dev->device,"no support for 10-bit address\n" ); +return -EINVAL ; + } + + *addr = (msg->addr <<1 ) &0xfe ;
I don't see what difference the & 0xfe makes. I think you can drop that.
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ +if (msg->flags &I2C_M_RD ) + *addr |=1 ; + +return 0 ; +} + +static int bcm_iproc_i2c_check_status (struct bcm_iproc_i2c_dev *dev) +{ +u32 val;
drivers/i2c/busses/i2c-bcm-iproc.c line 166
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ + val =readl (dev->base +M_CMD_OFFSET ); + val = (val >>M_CMD_STATUS_SHIFT ) &M_CMD_STATUS_MASK ; + +switch (val) { +case M_CMD_STATUS_SUCCESS : +return 0 ; + +case M_CMD_STATUS_LOST_ARB : +dev_err (dev->device,"lost bus arbitration\n" );
I wouldn't dev_err that, only dev_dbg. I'm not sure how usual the errors for the next two cases is, maybe degrade them to dev_dbg, too?
Quoted 58 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +58
-0+return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_ADDR : +dev_err (dev->device,"NAK addr:0x%02x\n" , dev->msg->addr); +return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_DATA : +dev_err (dev->device,"NAK data\n" ); +return -EREMOTEIO ; + +case M_CMD_STATUS_TIMEOUT : +dev_err (dev->device,"bus timeout\n" ); +return -ETIMEDOUT ; + +default : +dev_err (dev->device,"unknown error code=%d\n" , val); +return -EREMOTEIO ; + } + +return -EREMOTEIO ; +} + +static int bcm_iproc_i2c_xfer_single_msg (struct bcm_iproc_i2c_dev *dev, +struct i2c_msg *msg) +{ +int ret, i; +u8 addr; +u32 val; +unsigned long time_left =msecs_to_jiffies (I2C_TIMEOUT_MESC ); + +if (msg->len <1 || msg->len >M_TX_RX_FIFO_SIZE -1 ) { +dev_err (dev->device, +"supported data length is 1 - %u bytes\n" , +M_TX_RX_FIFO_SIZE -1 ); +return -EINVAL ; + } + + dev->msg = msg; + ret =__wait_for_bus_idle (dev); +if (ret) +return ret; + + ret =bcm_iproc_i2c_format_addr (dev, msg, &addr); +if (ret) +return ret; + +/* load slave address into the TX FIFO */ +writel (addr, dev->base +M_TX_OFFSET ); + +/* for a write transaction, load data into the TX FIFO */ +if (!(msg->flags &I2C_M_RD )) { +for (i =0 ; i < msg->len; i++) { + val = msg->buf[i]; + +/* mark the last byte */ +if (i == msg->len -1 ) + val |=1 <<M_TX_WR_STATUS_SHIFT ; +
drivers/i2c/busses/i2c-bcm-iproc.c line 234
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+writel (val, dev->base +M_TX_OFFSET ); + } + } + +/* mark as incomplete before starting the transaction */ +reinit_completion (&dev->done); + +/* +* Enable the "start busy" interrupt, which will be triggered after +* the transaction is done
This sound's wrong. I'd expect "start busy" to trigger as soon as the controller gets hold of the bus.
Quoted 86 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +86
-0+*/ +writel (1 <<IE_M_START_BUSY_SHIFT , dev->base +IE_OFFSET ); + +/* +* Now we can activate the transfer. For a read operation, specify the +* number of bytes to read +*/ + val =1 <<M_CMD_START_BUSY_SHIFT ; +if (msg->flags &I2C_M_RD ) { + val |= (M_CMD_PROTOCOL_BLK_RD <<M_CMD_PROTOCOL_SHIFT ) | + (msg->len <<M_CMD_RD_CNT_SHIFT ); + }else { + val |= (M_CMD_PROTOCOL_BLK_WR <<M_CMD_PROTOCOL_SHIFT ); + } +writel (val, dev->base +M_CMD_OFFSET ); + + time_left =wait_for_completion_timeout (&dev->done, time_left); + +/* disable all interrupts */ +writel (0 , dev->base +IE_OFFSET ); + +if (!time_left) { +dev_err (dev->device,"transaction times out\n" ); + +/* flush FIFOs */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | + (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, dev->base +M_FIFO_CTRL_OFFSET ); +return -EREMOTEIO ; + } + + ret =bcm_iproc_i2c_check_status (dev); +if (ret) { +/* flush both TX/RX FIFOs */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | + (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, dev->base +M_FIFO_CTRL_OFFSET ); +return ret; + } + +/* +* For a read operation, we now need to load the data from FIFO +* into the memory buffer +*/ +if (msg->flags &I2C_M_RD ) { +for (i =0 ; i < msg->len; i++) { + msg->buf[i] = (readl (dev->base +M_RX_OFFSET ) >> +M_RX_DATA_SHIFT ) &M_RX_DATA_MASK ; + } + } + +dev_dbg (dev->device,"xfer %c, addr=0x%02x, len=%d\n" , + (msg->flags &I2C_M_RD ) ?'R' :'W' , msg->addr, + msg->len); +dev_dbg (dev->device,"**** data start ****\n" ); +for (i =0 ; i < msg->len; i++) +dev_dbg (dev->device,"0x%02x " , msg->buf[i]); +dev_dbg (dev->device,"**** data end ****\n" ); + +return 0 ; +} + +static int bcm_iproc_i2c_xfer (struct i2c_adapter *adapter, +struct i2c_msg msgs[],int num) +{ +struct bcm_iproc_i2c_dev *dev =i2c_get_adapdata (adapter); +int ret, i; + +/* go through all messages */ +for (i =0 ; i < num; i++) { + ret =bcm_iproc_i2c_xfer_single_msg (dev, &msgs[i]); +if (ret) { +dev_err (dev->device,"xfer failed\n" ); +return ret; + } + } + +return num; +} + +static uint32_t bcm_iproc_i2c_functionality (struct i2c_adapter *adap) +{ +return I2C_FUNC_I2C |I2C_FUNC_SMBUS_EMUL ; +} + +static const struct i2c_algorithm bcm_iproc_algo = {
drivers/i2c/busses/i2c-bcm-iproc.c line 330
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ .master_xfer = bcm_iproc_i2c_xfer, + .functionality = bcm_iproc_i2c_functionality, +}; + +static int bcm_iproc_i2c_cfg_speed (struct bcm_iproc_i2c_dev *dev) +{ +unsigned int bus_speed, speed_bit; +u32 val; +int ret =of_property_read_u32 (dev->device->of_node,"clock-frequency" , + &bus_speed);
Inconsistent coding style. At most other places you use 2 tabs to indent a continued line. (Well you use this style for breaks in function declarations. Using the same style for both cases would be nice.)
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+if (ret <0 ) { +dev_err (dev->device,"missing clock-frequency property\n" ); +return -ENODEV ; + } + +switch (bus_speed) { +case 100000 : + speed_bit =0 ;
drivers/i2c/busses/i2c-bcm-iproc.c line 348
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+break ; +case 400000 : + speed_bit =1 ; +break ; +default : +dev_err (dev->device,"%d Hz bus speed not supported\n" , + bus_speed); +dev_err (dev->device,"valid speeds are 100khz and 400khz\n" ); +return -EINVAL ; + }
I'd be more graceful here:
if (bus_speed < 100000) error_out; else if (bus_speed < 400000) speed_bit = 0; else /* >= 400000 */ speed_bit = 1;
Quoted 16 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +16
-0+ + val =readl (dev->base +TIM_CFG_OFFSET ); + val &= ~(1 <<TIME_CFG_MODE_400_SHIFT ); + val |= speed_bit <<TIME_CFG_MODE_400_SHIFT ; +writel (val, dev->base +TIM_CFG_OFFSET ); + +dev_info (dev->device,"bus set to %u Hz\n" , bus_speed); + +return 0 ; +} + +static int bcm_iproc_i2c_init (struct bcm_iproc_i2c_dev *dev) +{ +u32 val; + +/* put controller in reset */
drivers/i2c/busses/i2c-bcm-iproc.c line 374
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ val =readl (dev->base +CFG_OFFSET ); + val |=1 <<CFG_RESET_SHIFT ; + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, dev->base +CFG_OFFSET ); + +/* wait 100 usec per spec */ +udelay (100 ); + +/* bring controller out of reset */ + val =readl (dev->base +CFG_OFFSET );
Is it necessary to reread the register value here?
drivers/i2c/busses/i2c-bcm-iproc.c line 384
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ val &= ~(1 <<CFG_RESET_SHIFT ); +writel (val, dev->base +CFG_OFFSET ); + +/* flush TX/RX FIFOs and set RX FIFO threshold to zero */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, dev->base +M_FIFO_CTRL_OFFSET ); + +/* disable all interrupts */ + val =0 ; +writel (val, dev->base +IE_OFFSET );
writel(0, dev->base + IE_OFFSET);
drivers/i2c/busses/i2c-bcm-iproc.c line 388
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +3
-0+/* clear all pending interrupts */ + val =readl (dev->base +IS_OFFSET ); +writel (val, dev->base +IS_OFFSET );
writel(0xffffffff, dev->base + IS_OFFSET); ??
Quoted 16 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +16
-0+ +return 0 ; +} + +static void bcm_iproc_i2c_enable (struct bcm_iproc_i2c_dev *dev) +{ +u32 val; + + val =readl (dev->base +CFG_OFFSET ); + val |=1 <<CFG_EN_SHIFT ; +writel (val, dev->base +CFG_OFFSET ); +} + +static void bcm_iproc_i2c_disable (struct bcm_iproc_i2c_dev *dev) +{ +u32 val;
drivers/i2c/busses/i2c-bcm-iproc.c line 414
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ + val =readl (dev->base +CFG_OFFSET ); + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, dev->base +CFG_OFFSET ); +} + +static int bcm_iproc_i2c_probe (struct platform_device *pdev) +{ +int irq, ret =0 ; +struct bcm_iproc_i2c_dev *dev;
"dev" is a misleading name here. I'd call this
bcm_iproc_i2c_ddata *ddata;
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+struct i2c_adapter *adap; +struct resource *res; + + dev =devm_kzalloc (&pdev->dev,sizeof (*dev),GFP_KERNEL ); +if (!dev)
drivers/i2c/busses/i2c-bcm-iproc.c line 429
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+return -ENOMEM ; + +platform_set_drvdata (pdev, dev); + dev->device = &pdev->dev; +init_completion (&dev->done); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + dev->base =devm_ioremap_resource (dev->device, res); +if (IS_ERR (dev->base)) +return -ENOMEM ;
return PTR_ERR(dev->base);
drivers/i2c/busses/i2c-bcm-iproc.c line 440
Quoted 11 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +11
-0+ + ret =bcm_iproc_i2c_init (dev); +if (ret) +return ret; + + ret =bcm_iproc_i2c_cfg_speed (dev); +if (ret) +return ret; + + irq =platform_get_irq (pdev,0 ); +if (irq <0 ) {
irq == 0 should be handled as error, too.
Quoted 17 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +17
-0+dev_err (dev->device,"no irq resource\n" ); +return irq; + } + + ret =devm_request_irq (&pdev->dev, irq, bcm_iproc_i2c_isr, +IRQF_SHARED , pdev->name, dev); +if (ret) { +dev_err (dev->device,"unable to request irq %i\n" , irq); +return ret; + } + +bcm_iproc_i2c_enable (dev); + + adap = &dev->adapter; +i2c_set_adapdata (adap, dev); +strlcpy (adap->name,"Broadcom iProc I2C adapter" ,sizeof (adap->name)); + adap->algo = &bcm_iproc_algo;
drivers/i2c/busses/i2c-bcm-iproc.c line 467
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + + ret =i2c_add_adapter (adap); +if (ret) { +dev_err (dev->device,"failed to add adapter\n" ); +return ret; + } + +dev_info (dev->device,"device registered successfully\n" );
This just clutters the boot log. Please remove.
drivers/i2c/busses/i2c-bcm-iproc.c line 477
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ +return 0 ; +} + +static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *dev =platform_get_drvdata (pdev); + +i2c_del_adapter (&dev->adapter); +bcm_iproc_i2c_disable (dev);
I think you have a problem here if bcm_iproc_i2c_remove is called while an irq is still being serviced. I'm not sure how to prevent this properly for a shared interrupt.
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+ +return 0 ; +} + +static const struct of_device_id bcm_iproc_i2c_of_match[] = {
drivers/i2c/busses/i2c-bcm-iproc.c line 492
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ {.compatible = "brcm,iproc-i2c",}, + {}, +}; +MODULE_DEVICE_TABLE (of, bcm_iproc_i2c_of_match); + +static struct platform_driver bcm_iproc_i2c_driver = { + .driver = { + .name ="bcm-iproc-i2c" , + .of_match_table = bcm_iproc_i2c_of_match, + },
Inconsistent indention.
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+ .probe = bcm_iproc_i2c_probe, + .remove = bcm_iproc_i2c_remove, +}; +module_platform_driver (bcm_iproc_i2c_driver); + +MODULE_AUTHOR ("Ray Jui <[email protected]>" ); +MODULE_DESCRIPTION ("Broadcom iProc I2C Driver" ); +MODULE_LICENSE ("GPL v2" );
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Ray Jui
maintainerRe: [PATCH v3 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 34 lines · Uwe Kleine-K?nig
Hello,
Quoted 21 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 500 ++++++++++++++++++++++++++++++++++++ 3 files changed, 511 insertions(+) create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.cdrivers/i2c/busses/Kconfig +0
-0drivers/i2c/busses/Kconfig config I2C_BCM2835 · line 378
Quoted 7 lines
drivers/i2c/busses/Kconfig +4
-0@@ -372,6 +372,16 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC + default yIt would be nice to have the following here to improve compile coverage testing:
Quoted 3 lines
depends on ARCH_BCM_IPROC || COMPILE_TEST default ARCH_BCM_IPROC
Sure will do!
Quoted 151 lines
Quoted 151 lines
drivers/i2c/busses/Kconfig +6
-0+ help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILEdrivers/i2c/busses/Makefile +1
-0@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.odrivers/i2c/busses/i2c-bcm-iproc.c new file +124
-0@@ -0,0 +1,500 @@ +/* +* Copyright (C) 2014 Broadcom Corporation +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/delay.h> + +#define CFG_OFFSET 0x00 +#define CFG_RESET_SHIFT 31 +#define CFG_EN_SHIFT 30 +#define CFG_M_RETRY_CNT_SHIFT 16 +#define CFG_M_RETRY_CNT_MASK 0x0f + +#define TIM_CFG_OFFSET 0x04 +#define TIME_CFG_MODE_400_SHIFT 31 + +#define M_FIFO_CTRL_OFFSET 0x0c +#define M_FIFO_RX_FLUSH_SHIFT 31 +#define M_FIFO_TX_FLUSH_SHIFT 30 +#define M_FIFO_RX_CNT_SHIFT 16 +#define M_FIFO_RX_CNT_MASK 0x7f +#define M_FIFO_RX_THLD_SHIFT 8 +#define M_FIFO_RX_THLD_MASK 0x3f + +#define M_CMD_OFFSET 0x30 +#define M_CMD_START_BUSY_SHIFT 31 +#define M_CMD_STATUS_SHIFT 25 +#define M_CMD_STATUS_MASK 0x07 +#define M_CMD_STATUS_SUCCESS 0x0 +#define M_CMD_STATUS_LOST_ARB 0x1 +#define M_CMD_STATUS_NACK_ADDR 0x2 +#define M_CMD_STATUS_NACK_DATA 0x3 +#define M_CMD_STATUS_TIMEOUT 0x4 +#define M_CMD_PROTOCOL_SHIFT 9 +#define M_CMD_PROTOCOL_MASK 0xf +#define M_CMD_PROTOCOL_BLK_WR 0x7 +#define M_CMD_PROTOCOL_BLK_RD 0x8 +#define M_CMD_PEC_SHIFT 8 +#define M_CMD_RD_CNT_SHIFT 0 +#define M_CMD_RD_CNT_MASK 0xff + +#define IE_OFFSET 0x38 +#define IE_M_RX_FIFO_FULL_SHIFT 31 +#define IE_M_RX_THLD_SHIFT 30 +#define IE_M_START_BUSY_SHIFT 28 + +#define IS_OFFSET 0x3c +#define IS_M_RX_FIFO_FULL_SHIFT 31 +#define IS_M_RX_THLD_SHIFT 30 +#define IS_M_START_BUSY_SHIFT 28 + +#define M_TX_OFFSET 0x40 +#define M_TX_WR_STATUS_SHIFT 31 +#define M_TX_DATA_SHIFT 0 +#define M_TX_DATA_MASK 0xff + +#define M_RX_OFFSET 0x44 +#define M_RX_STATUS_SHIFT 30 +#define M_RX_STATUS_MASK 0x03 +#define M_RX_PEC_ERR_SHIFT 29 +#define M_RX_DATA_SHIFT 0 +#define M_RX_DATA_MASK 0xff + +#define I2C_TIMEOUT_MESC 100 +#define M_TX_RX_FIFO_SIZE 64 + +enum bus_speed_index { +I2C_SPD_100K =0 , +I2C_SPD_400K , +}; + +struct bcm_iproc_i2c_dev { +struct device *device; + +void __iomem *base; +struct i2c_msg *msg; + +struct i2c_adapter adapter; + +struct completion done; +}; + +/* +* Can be expanded in the future if more interrupt status bits are utilized +*/ +#define ISR_MASK (1 << IS_M_START_BUSY_SHIFT) + +static irqreturn_t bcm_iproc_i2c_isr (int irq,void *data) +{ +struct bcm_iproc_i2c_dev *dev = data; +u32 status =readl (dev->base +IS_OFFSET ); + + status &=ISR_MASK ; + +if (!status) +return IRQ_NONE ; + +writel (status, dev->base +IS_OFFSET ); +complete_all (&dev->done); + +return IRQ_HANDLED ; +} + +static int __wait_for_bus_idle (struct bcm_iproc_i2c_dev *dev) +{ +unsigned long timeout = jiffies +msecs_to_jiffies (I2C_TIMEOUT_MESC );
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 131
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+ +while (readl (dev->base +M_CMD_OFFSET ) & + (1 <<M_CMD_START_BUSY_SHIFT )) { +if (time_after (jiffies, timeout)) { +dev_err (dev->device,"wait for bus idle timeout\n" ); +return -ETIMEDOUT ; + }Add a call to
cpu_relaxhere. Do you really need a tight loop here?
Yes, thanks!
Quoted 8 lines
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+ } + +return 0 ; +} + +static int bcm_iproc_i2c_format_addr (struct bcm_iproc_i2c_dev *dev, +struct i2c_msg *msg,u8 *addr) +{
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 146
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+ +if (msg->flags &I2C_M_TEN ) { +dev_err (dev->device,"no support for 10-bit address\n" ); +return -EINVAL ; + } + + *addr = (msg->addr <<1 ) &0xfe ;I don't see what difference the &
0xfemakes. I think you can drop that.
Yeah just see this now. Thanks!
Quoted 14 lines
Quoted 14 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +14
-0+ +if (msg->flags &I2C_M_RD ) + *addr |=1 ; + +return 0 ; +} + +static int bcm_iproc_i2c_check_status (struct bcm_iproc_i2c_dev *dev) +{ +u32 val; + + val =readl (dev->base +M_CMD_OFFSET ); + val = (val >>M_CMD_STATUS_SHIFT ) &M_CMD_STATUS_MASK ; +
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 166
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+switch (val) { +case M_CMD_STATUS_SUCCESS : +return 0 ; + +case M_CMD_STATUS_LOST_ARB : +dev_err (dev->device,"lost bus arbitration\n" );I wouldn't
dev_errthat, onlydev_dbg. I'm not sure how usual the errors for the next two cases is, maybe degrade them todev_dbg, too?
These errors are rare, and it's nice to keep them at the dev_err level so the user will be more aware.
Quoted 62 lines
Quoted 62 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +62
-0+return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_ADDR : +dev_err (dev->device,"NAK addr:0x%02x\n" , dev->msg->addr); +return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_DATA : +dev_err (dev->device,"NAK data\n" ); +return -EREMOTEIO ; + +case M_CMD_STATUS_TIMEOUT : +dev_err (dev->device,"bus timeout\n" ); +return -ETIMEDOUT ; + +default : +dev_err (dev->device,"unknown error code=%d\n" , val); +return -EREMOTEIO ; + } + +return -EREMOTEIO ; +} + +static int bcm_iproc_i2c_xfer_single_msg (struct bcm_iproc_i2c_dev *dev, +struct i2c_msg *msg) +{ +int ret, i; +u8 addr; +u32 val; +unsigned long time_left =msecs_to_jiffies (I2C_TIMEOUT_MESC ); + +if (msg->len <1 || msg->len >M_TX_RX_FIFO_SIZE -1 ) { +dev_err (dev->device, +"supported data length is 1 - %u bytes\n" , +M_TX_RX_FIFO_SIZE -1 ); +return -EINVAL ; + } + + dev->msg = msg; + ret =__wait_for_bus_idle (dev); +if (ret) +return ret; + + ret =bcm_iproc_i2c_format_addr (dev, msg, &addr); +if (ret) +return ret; + +/* load slave address into the TX FIFO */ +writel (addr, dev->base +M_TX_OFFSET ); + +/* for a write transaction, load data into the TX FIFO */ +if (!(msg->flags &I2C_M_RD )) { +for (i =0 ; i < msg->len; i++) { + val = msg->buf[i]; + +/* mark the last byte */ +if (i == msg->len -1 ) + val |=1 <<M_TX_WR_STATUS_SHIFT ; + +writel (val, dev->base +M_TX_OFFSET ); + } + } +
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 234
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+/* mark as incomplete before starting the transaction */ +reinit_completion (&dev->done); + +/* +* Enable the "start busy" interrupt, which will be triggered after +* the transaction is done This sound's wrong. I'd expect "start busy" to trigger as soon as the controller gets hold of the bus.
Okay maybe the naming is misleading. But this is the real name used in the register description from the datasheet. I'll add more comment in the code to make it more clear.
Basically this enables the interrupt that triggers when the controller internal start_busy bit transitions from 1 to 0, i.e., after a transaction finishes. The interrupt won't be triggered when a new transaction starts since it causes the start_busy bit to transit from 0 to 1.
Quoted 91 lines
Quoted 91 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +91
-0+*/ +writel (1 <<IE_M_START_BUSY_SHIFT , dev->base +IE_OFFSET ); + +/* +* Now we can activate the transfer. For a read operation, specify the +* number of bytes to read +*/ + val =1 <<M_CMD_START_BUSY_SHIFT ; +if (msg->flags &I2C_M_RD ) { + val |= (M_CMD_PROTOCOL_BLK_RD <<M_CMD_PROTOCOL_SHIFT ) | + (msg->len <<M_CMD_RD_CNT_SHIFT ); + }else { + val |= (M_CMD_PROTOCOL_BLK_WR <<M_CMD_PROTOCOL_SHIFT ); + } +writel (val, dev->base +M_CMD_OFFSET ); + + time_left =wait_for_completion_timeout (&dev->done, time_left); + +/* disable all interrupts */ +writel (0 , dev->base +IE_OFFSET ); + +if (!time_left) { +dev_err (dev->device,"transaction times out\n" ); + +/* flush FIFOs */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | + (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, dev->base +M_FIFO_CTRL_OFFSET ); +return -EREMOTEIO ; + } + + ret =bcm_iproc_i2c_check_status (dev); +if (ret) { +/* flush both TX/RX FIFOs */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | + (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, dev->base +M_FIFO_CTRL_OFFSET ); +return ret; + } + +/* +* For a read operation, we now need to load the data from FIFO +* into the memory buffer +*/ +if (msg->flags &I2C_M_RD ) { +for (i =0 ; i < msg->len; i++) { + msg->buf[i] = (readl (dev->base +M_RX_OFFSET ) >> +M_RX_DATA_SHIFT ) &M_RX_DATA_MASK ; + } + } + +dev_dbg (dev->device,"xfer %c, addr=0x%02x, len=%d\n" , + (msg->flags &I2C_M_RD ) ?'R' :'W' , msg->addr, + msg->len); +dev_dbg (dev->device,"**** data start ****\n" ); +for (i =0 ; i < msg->len; i++) +dev_dbg (dev->device,"0x%02x " , msg->buf[i]); +dev_dbg (dev->device,"**** data end ****\n" ); + +return 0 ; +} + +static int bcm_iproc_i2c_xfer (struct i2c_adapter *adapter, +struct i2c_msg msgs[],int num) +{ +struct bcm_iproc_i2c_dev *dev =i2c_get_adapdata (adapter); +int ret, i; + +/* go through all messages */ +for (i =0 ; i < num; i++) { + ret =bcm_iproc_i2c_xfer_single_msg (dev, &msgs[i]); +if (ret) { +dev_err (dev->device,"xfer failed\n" ); +return ret; + } + } + +return num; +} + +static uint32_t bcm_iproc_i2c_functionality (struct i2c_adapter *adap) +{ +return I2C_FUNC_I2C |I2C_FUNC_SMBUS_EMUL ; +} + +static const struct i2c_algorithm bcm_iproc_algo = { + .master_xfer = bcm_iproc_i2c_xfer, + .functionality = bcm_iproc_i2c_functionality, +}; + +static int bcm_iproc_i2c_cfg_speed (struct bcm_iproc_i2c_dev *dev)
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 330
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+{ +unsigned int bus_speed, speed_bit; +u32 val; +int ret =of_property_read_u32 (dev->device->of_node,"clock-frequency" , + &bus_speed);Inconsistent coding style. At most other places you use 2 tabs to indent a continued line. (Well you use this style for breaks in function declarations. Using the same style for both cases would be nice.)
Will try to use this style for both continued lines and function declarations. Thanks!
Quoted 20 lines
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+if (ret <0 ) { +dev_err (dev->device,"missing clock-frequency property\n" ); +return -ENODEV ; + } + +switch (bus_speed) { +case 100000 : + speed_bit =0 ;drivers/i2c/busses/i2c-bcm-iproc.c line 348
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+break ; +case 400000 : + speed_bit =1 ; +break ; +default : +dev_err (dev->device,"%d Hz bus speed not supported\n" , + bus_speed); +dev_err (dev->device,"valid speeds are 100khz and 400khz\n" ); +return -EINVAL ; + }I'd be more graceful here:
Quoted 8 lines
if (bus_speed < 100000) error_out; else if (bus_speed < 400000) speed_bit = 0; else /* >= 400000 */ speed_bit = 1;
Okay I can do that. Thanks.
Quoted 19 lines
Quoted 19 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +19
-0+ + val =readl (dev->base +TIM_CFG_OFFSET ); + val &= ~(1 <<TIME_CFG_MODE_400_SHIFT ); + val |= speed_bit <<TIME_CFG_MODE_400_SHIFT ; +writel (val, dev->base +TIM_CFG_OFFSET ); + +dev_info (dev->device,"bus set to %u Hz\n" , bus_speed); + +return 0 ; +} + +static int bcm_iproc_i2c_init (struct bcm_iproc_i2c_dev *dev) +{ +u32 val; + +/* put controller in reset */ + val =readl (dev->base +CFG_OFFSET ); + val |=1 <<CFG_RESET_SHIFT ; + val &= ~(1 <<CFG_EN_SHIFT );
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 374
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+writel (val, dev->base +CFG_OFFSET ); + +/* wait 100 usec per spec */ +udelay (100 ); + +/* bring controller out of reset */ + val =readl (dev->base +CFG_OFFSET );Is it necessary to reread the register value here?
I guess not, since there's no one else modifies this register. Will get rid of the redundant read here. Thanks!
Quoted 12 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 384
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ val &= ~(1 <<CFG_RESET_SHIFT ); +writel (val, dev->base +CFG_OFFSET ); + +/* flush TX/RX FIFOs and set RX FIFO threshold to zero */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, dev->base +M_FIFO_CTRL_OFFSET ); + +/* disable all interrupts */ + val =0 ; +writel (val, dev->base +IE_OFFSET );
writel(0, dev->base + IE_OFFSET);
Right.
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 388
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +3
-0+/* clear all pending interrupts */ + val =readl (dev->base +IS_OFFSET ); +writel (val, dev->base +IS_OFFSET );
writel(0xffffffff, dev->base + IS_OFFSET); ??
Yes, better.
Quoted 28 lines
Quoted 16 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +16
-0+ +return 0 ; +} + +static void bcm_iproc_i2c_enable (struct bcm_iproc_i2c_dev *dev) +{ +u32 val; + + val =readl (dev->base +CFG_OFFSET ); + val |=1 <<CFG_EN_SHIFT ; +writel (val, dev->base +CFG_OFFSET ); +} + +static void bcm_iproc_i2c_disable (struct bcm_iproc_i2c_dev *dev) +{ +u32 val;drivers/i2c/busses/i2c-bcm-iproc.c line 414
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ + val =readl (dev->base +CFG_OFFSET ); + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, dev->base +CFG_OFFSET ); +} + +static int bcm_iproc_i2c_probe (struct platform_device *pdev) +{ +int irq, ret =0 ; +struct bcm_iproc_i2c_dev *dev;"dev" is a misleading name here. I'd call this
Quoted 2 lines
bcm_iproc_i2c_ddata *ddata;
I will change it to iproc_i2c;
Quoted 8 lines
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+struct i2c_adapter *adap; +struct resource *res; + + dev =devm_kzalloc (&pdev->dev,sizeof (*dev),GFP_KERNEL ); +if (!dev) +return -ENOMEM ; + +platform_set_drvdata (pdev, dev);
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 429
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+ dev->device = &pdev->dev; +init_completion (&dev->done); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + dev->base =devm_ioremap_resource (dev->device, res); +if (IS_ERR (dev->base)) +return -ENOMEM ;return PTR_ERR(dev->base);
Okay. Thanks.
Quoted 4 lines
Quoted 4 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +4
-0+ + ret =bcm_iproc_i2c_init (dev); +if (ret) +return ret;
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 440
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+ + ret =bcm_iproc_i2c_cfg_speed (dev); +if (ret) +return ret; + + irq =platform_get_irq (pdev,0 ); +if (irq <0 ) {irq == 0 should be handled as error, too.
Ah. I thought zero is a valid global interrupt number, and I see other drivers checking against < 0 as well. Is my understanding incorrect?
Quoted 20 lines
Quoted 20 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +20
-0+dev_err (dev->device,"no irq resource\n" ); +return irq; + } + + ret =devm_request_irq (&pdev->dev, irq, bcm_iproc_i2c_isr, +IRQF_SHARED , pdev->name, dev); +if (ret) { +dev_err (dev->device,"unable to request irq %i\n" , irq); +return ret; + } + +bcm_iproc_i2c_enable (dev); + + adap = &dev->adapter; +i2c_set_adapdata (adap, dev); +strlcpy (adap->name,"Broadcom iProc I2C adapter" ,sizeof (adap->name)); + adap->algo = &bcm_iproc_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; +
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 467
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+ ret =i2c_add_adapter (adap); +if (ret) { +dev_err (dev->device,"failed to add adapter\n" ); +return ret; + } + +dev_info (dev->device,"device registered successfully\n" );This just clutters the boot log. Please remove.
Okay.
Quoted 5 lines
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+ +return 0 ; +} + +static int bcm_iproc_i2c_remove (struct platform_device *pdev)
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 477
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+{ +struct bcm_iproc_i2c_dev *dev =platform_get_drvdata (pdev); + +i2c_del_adapter (&dev->adapter); +bcm_iproc_i2c_disable (dev);I think you have a problem here if
bcm_iproc_i2c_removeis called while an irq is still being serviced. I'm not sure how to prevent this properly for a shared interrupt.
Can I grab i2c_lock_adapter to ensure the bus is locked (so there's no outstanding transactions or IRQs by the time we remove the adapter)? But I see no I2C bus driver does this in their remove function...
Quoted 8 lines
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+ +return 0 ; +} + +static const struct of_device_id bcm_iproc_i2c_of_match[] = { + {.compatible ="brcm,iproc-i2c" ,}, + {}, +};
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 492
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+MODULE_DEVICE_TABLE (of, bcm_iproc_i2c_of_match); + +static struct platform_driver bcm_iproc_i2c_driver = { + .driver = { + .name ="bcm-iproc-i2c" , + .of_match_table = bcm_iproc_i2c_of_match, + },Inconsistent indention.
Sorry. Will fix.
Quoted 9 lines
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+ .probe = bcm_iproc_i2c_probe, + .remove = bcm_iproc_i2c_remove, +}; +module_platform_driver (bcm_iproc_i2c_driver); + +MODULE_AUTHOR ("Ray Jui <[email protected]>" ); +MODULE_DESCRIPTION ("Broadcom iProc I2C Driver" ); +MODULE_LICENSE ("GPL v2" );
Re: [PATCH v3 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Hello,
Quoted 6 lines · Ray Jui
Quoted 4 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 440
Quoted 2 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +2
-0+ irq =platform_get_irq (pdev,0 ); +if (irq <0 ) {irq == 0 should be handled as error, too.
Ah. I thought zero is a valid global interrupt number, and I see other drivers checking against < 0 as well. Is my understanding incorrect?
These are wrong, too. 0 should never be a valid interrupt number. There are some exceptions but mostly for historic reasons. The right handling is used for example in drivers/i2c/busses/i2c-efm32.c.
Quoted 14 lines
Quoted 3 lines
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +3
-0+dev_err (dev->device,"no irq resource\n" ); +return irq; + }[...]
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 477
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *dev =platform_get_drvdata (pdev); + +i2c_del_adapter (&dev->adapter); +bcm_iproc_i2c_disable (dev);I think you have a problem here if
bcm_iproc_i2c_removeis called while an irq is still being serviced. I'm not sure how to prevent this properly for a shared interrupt.
Quoted 3 lines
Can I grab
i2c_lock_adapterto ensure the bus is locked (so there's no outstanding transactions or IRQs by the time we remove the adapter)? But I see no I2C bus driver does this in their remove function...
The problem I pointed out is the reason for some driver authors not to use devm_request_irq. If you use plain request_irq and the matching free_irq in the .remove callback you can be sure that the irq isn't running any more as soon as free_irq returns.
BTW, if you use vim, you can add
set cinoptions=(,:
if has("autocmd")
filetype plugin indent on
endif
to your .vimrc. Then while typing vim does the indention right and consistent, and with the = command you can reindent.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Ray Jui
maintainerRe: [PATCH v3 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 7 lines · Uwe Kleine-K?nig
Hello,
Quoted 4 lines · Ray Jui
Quoted 4 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 440
Quoted 2 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +2
-0+ irq =platform_get_irq (pdev,0 ); +if (irq <0 ) {irq == 0 should be handled as error, too.
Quoted 6 lines
Quoted 2 lines
Ah. I thought zero is a valid global interrupt number, and I see other drivers checking against < 0 as well. Is my understanding incorrect?
These are wrong, too. 0 should never be a valid interrupt number. There are some exceptions but mostly for historic reasons. The right handling is used for example in
drivers/i2c/busses/i2c-efm32.c.
Okay. Will check against <= 0. Thanks.
Quoted 14 lines
Quoted 14 lines
Quoted 3 lines
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +3
-0+dev_err (dev->device,"no irq resource\n" ); +return irq; + }[...]
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 477
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *dev =platform_get_drvdata (pdev); + +i2c_del_adapter (&dev->adapter); +bcm_iproc_i2c_disable (dev);I think you have a problem here if
bcm_iproc_i2c_removeis called while an irq is still being serviced. I'm not sure how to prevent this properly for a shared interrupt.
Quoted 8 lines
Quoted 3 lines
Can I grab
i2c_lock_adapterto ensure the bus is locked (so there's no outstanding transactions or IRQs by the time we remove the adapter)? But I see no I2C bus driver does this in their remove function...The problem I pointed out is the reason for some driver authors not to use
devm_request_irq. If you use plainrequest_irqand the matchingfree_irqin the .remove callback you can be sure that the irq isn't running any more as soon asfree_irqreturns.
Okay. Will change to use request_irq and make sure that it's freed in the remove function. Also, the interrupt is dedicated to the I2C controller, so I'll remove the IRQF_SHARED flag.
Quoted 10 lines
BTW, if you use vim, you can add
set cinoptions=(,:
ifhas("autocmd")
filetype plugin indent on
endifto your .vimrc. Then while typing vim does the indention right and consistent, and with the = command you can reindent.
Wow this is excellent! Just tried and it works perfectly. Thanks a lot!!!
Quoted 3 lines
Best regards
Uwe
Re: [PATCH v3 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Ray JuiQuoted 7 lines
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 166
Quoted 2 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +2
-0+case M_CMD_STATUS_LOST_ARB : +dev_err (dev->device,"lost bus arbitration\n" );I wouldn't
dev_errthat, onlydev_dbg. I'm not sure how usual the errors for the next two cases is, maybe degrade them todev_dbg, too?These errors are rare, and it's nice to keep them at the
dev_errlevel so the user will be more aware.
This is wrong. Arbitration lost and NACK is pretty standard stuff on an I2C bus. User doesn't need to know about it, it is just noise in the logs. Timeout is different, you can report that (although I should probably move such a message into the core). Please also use the proper errno codes defined in Documentation/i2c/fault-codes. They should be distinct enough to drop the messages.
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +13
-0+return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_ADDR : +dev_err (dev->device,"NAK addr:0x%02x\n" , dev->msg->addr); +return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_DATA : +dev_err (dev->device,"NAK data\n" ); +return -EREMOTEIO ; + +case M_CMD_STATUS_TIMEOUT : +dev_err (dev->device,"bus timeout\n" ); +return -ETIMEDOUT ;
Quoted 8 lines
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 187
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+ +default : +dev_err (dev->device,"unknown error code=%d\n" , val); +return -EREMOTEIO ; + } + +return -EREMOTEIO ; +}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150115/bb1f03f7/attachment.sig>
Ray Jui
maintainerRe: [PATCH v3 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 8 lines · Wolfram Sang
Quoted 7 lines
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 166
Quoted 2 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +2
-0+case M_CMD_STATUS_LOST_ARB : +dev_err (dev->device,"lost bus arbitration\n" );I wouldn't
dev_errthat, onlydev_dbg. I'm not sure how usual the errors for the next two cases is, maybe degrade them todev_dbg, too?These errors are rare, and it's nice to keep them at the
dev_errlevel so the user will be more aware.
Quoted 7 lines
This is wrong. Arbitration lost and NACK is pretty standard stuff on an I2C bus. User doesn't need to know about it, it is just noise in the logs. Timeout is different, you can report that (although I should probably move such a message into the core). Please also use the proper errno codes defined in
Documentation/i2c/fault-codes. They should be distinct enough to drop the messages.
Okay will do.
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +21
-0+return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_ADDR : +dev_err (dev->device,"NAK addr:0x%02x\n" , dev->msg->addr); +return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_DATA : +dev_err (dev->device,"NAK data\n" ); +return -EREMOTEIO ; + +case M_CMD_STATUS_TIMEOUT : +dev_err (dev->device,"bus timeout\n" ); +return -ETIMEDOUT ; + +default : +dev_err (dev->device,"unknown error code=%d\n" , val); +return -EREMOTEIO ; + } + +return -EREMOTEIO ; +}
Ray Jui
maintainerPATCH v3 3/3 ARM: dts: add I2C device nodes for Broadcom Cygnus
In reply to Ray JuiAdd I2C device nodes and its properties in bcm-cygnus.dtsi but keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the future
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +20 -0
@@ -70,6 +70,26 @@ }; }; + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c@1800b000 { + compatible = "brcm,iproc-i2c"; + reg = <0x1800b000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + uart0: serial@18020000 { compatible = "snps,dw-apb-uart"; reg = <0x18020000 0x100>;
Signature · 1 line
1.7.9.5
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): 548F577E.7020207-dY08KVG/lbpWk0Htik3J/[email protected]
Re: [PATCH v3 0/3] Add I2C support to Broadcom iProc
Hi,
please don't drop the i2c-list.
Quoted 4 lines
I guess you are probably extremely busy and might not have had a chance to look into the iProc I2C driver v3 patch that was submitted on December 9. I'm not trying to rush it, and am perfectly fine with waiting longer. I understand subsystem maintainers like you are usually very busy.
True, true.
Quoted 2 lines
As I'm quite new to the upstreaming process, here I'd just like to find out in a bit more details on what to expect and how to proceed forward.
We are in the merge window currently, and I will start looking at new patches probably around rc2 or so.
If you want to speed up things, check the reviews of other new drivers I did in the recent past and check if some of the remarks also apply to your driver.
Thanks,
Wolfram
Re: [PATCH v3 0/3] Add I2C support to Broadcom iProc
Hi Wolfram,
Thanks for the reply. I'll go through your recent reviews and if I find any comment that applies to my driver I'll make the change.
Thanks,
Ray
Quoted 25 lines · Wolfram Sang
Hi,
please don't drop the i2c-list.
Quoted 4 lines
I guess you are probably extremely busy and might not have had a chance to look into the iProc I2C driver v3 patch that was submitted on December 9. I'm not trying to rush it, and am perfectly fine with waiting longer. I understand subsystem maintainers like you are usually very busy.
True, true.
Quoted 2 lines
As I'm quite new to the upstreaming process, here I'd just like to find out in a bit more details on what to expect and how to proceed forward.
We are in the merge window currently, and I will start looking at new patches probably around rc2 or so.
If you want to speed up things, check the reviews of other new drivers I did in the recent past and check if some of the remarks also apply to your driver.
Thanks,
Wolfram
Ray Jui
maintainerv5 cover Add gpio support to Broadcom Cygnus SoC
In reply to a message not in the archiveThis patchset contains the initial GPIO support for the Broadcom Cygnus SoC. Cygnus has 3 GPIO controllers: 1) the ASIU GPIO; 2) the chipCommonG GPIO; and 3) the ALWAYS-ON GPIO. All 3 types of GPIO controllers are supported by the same Cygnus GPIO driver
Changes from v4:
- Use DT property "linux,gpio-base" to define GPIO base number
- factorize common code to improve code readability and reduce code size
- remove "bcm_" prefix on function and struct names
- improve debugging prints
- default GPIO_BCM_CYGNUS to y in Kconfig (it still depends on ARCH_BCM_CYGNUS). This way we do not need to select it from the arch/arm/mach-bcm/Kconfig
- Get rid of redundant MAINTAINER entry for this driver. It will be maintained by Broadcom iProc/Cygnus maintainers
- Update device tree document based on driver changes
Changes from v3:
- Fix dt property tpyo
- Fix incorrect GPIO compatible ID in device tree binding document example
Changes from v2:
- Consolidate different compatible IDs into "brcm,cygnus-gpio"
- Get rid of redundant "no-interrupt" property
Changes from v1:
- Get rid of inline qualifier
- Get rid of redundant check in the ISR
- Other minor fixes to imrove code readability
Ray Jui (3):
gpio: Cygnus: define Broadcom Cygnus GPIO binding
gpio: Cygnus: add GPIO driver
ARM: dts: enable GPIO for Broadcom Cygnus
.../devicetree/bindings/gpio/brcm,cygnus-gpio.txt | 87 +++ arch/arm/boot/dts/bcm-cygnus.dtsi | 33 ++ drivers/gpio/Kconfig | 12 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-bcm-cygnus.c | 613 ++++++++++++++++++++ 5 files changed, 746 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt create mode 100644 drivers/gpio/gpio-bcm-cygnus.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v5 1/3 gpio: Cygnus: define Broadcom Cygnus GPIO binding
Document the GPIO device tree binding for Broadcom Cygnus SoC
--- .../devicetree/bindings/gpio/brcm,cygnus-gpio.txt | 87 ++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt new file +87 -0
@@ -0,0 +1,87 @@ +Broadcom Cygnus GPIO Controller + +Required properties: + +- compatible: + Must be "brcm,cygnus-gpio" + +- reg: + Define the base and range of the I/O address space that contain the Cygnus +GPIO controller registers + +- ngpios: + Total number of GPIOs the controller provides + +- linux,gpio-base: + Base GPIO number of this controller + +- #gpio-cells: + Must be two. The first cell is the GPIO pin number (within the +controller's domain) and the second cell is used for the following: + bit[0]: polarity (0 for normal and 1 for inverted) + bit[18:16]: internal pull up/down: 0 - pull up/down disabled + 1 - pull up enabled + 2 - pull down enabled + bit[22:20]: drive strength: 0 - 2 mA + 1 - 4 mA + 2 - 6 mA + 3 - 8 mA + 4 - 10 mA + 5 - 12 mA + 6 - 14 mA + 7 - 16 mA + +- gpio-controller: + Specifies that the node is a GPIO controller + +Optional properties: + +- interrupt-controller: + Specifies that the node is an interrupt controller. Not all Cygnus GPIO +interfaces support interrupt, e.g., the CRMU GPIO controller does not have its +interrupt routed to the main processor's GIC + +- interrupts: + The interrupt outputs from the GPIO controller. + +- no-drv-strength: + Specifies the GPIO controller does not support drive strength configuration + +Example: + gpio_asiu: gpio@180a5000 { + compatible = "brcm,cygnus-gpio"; + reg = <0x180a5000 0x668>; + ngpios = <122>; + linux,gpio-base = <0>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; + }; + + gpio_crmu: gpio@03024800 { + compatible = "brcm,cygnus-gpio"; + reg = <0x03024800 0x50>; + ngpios = <6>; + linux,gpio-base = <146>; + #gpio-cells = <2>; + gpio-controller; + no-drv-strength; + }; + + /* + * Touchscreen that uses the ASIU GPIO 100, with internal pull-up + * enabled + */ + tsc { + ... + ... + gpio-event = <&gpio_asiu 100 0x10000>; + }; + + /* Bluetooth that uses the CRMU GPIO 2, with polarity inverted */ + bluetooth { + ... + ... + bcm,rfkill-bank-sel = <&gpio_crmu 2 1> + }
Signature · 1 line
1.7.9.5
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt line 17
Quoted 5 lines · On Thursday 11 December 2014 16:05:04 Ray Jui wrote:
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt new file +4
-0+ +- linux,gpio-base: + Base GPIO number of this controller +
We've NAK'ed properties like this multiple times before, and it doesn't get any better this time. What are you trying to achieve here?
Arnd
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
Quoted 10 lines · Arnd Bergmann
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt line 17
Quoted 5 lines · On Thursday 11 December 2014 16:05:04 Ray Jui wrote:
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt new file +4
-0+ +- linux,gpio-base: + Base GPIO number of this controller +We've NAK'ed properties like this multiple times before, and it doesn't get any better this time. What are you trying to achieve here?
I am to blame for suggesting using this property to Ray, and I am fully aware that this has been rejected before, but look at what people came with recently to palliate the lack of control over the GPIO number space for DT platforms:
http://www.spinics.net/lists/arm-kernel/msg384847.html
https://lkml.org/lkml/2014/12/10/133
Right now GPIO numbering for platforms using DT is a very inconsistent process, subject to change by the simple action of adjusting the value of ARCH_NR_GPIOS (which we did recently, btw), adding a new GPIO controller, or changing the probe order of devices. For users of the integer or sysfs interfaces, this results in GPIO numbers that change, and drivers and/or user-space programs that behave incorrectly. Ironically, the only way to have consistent numbers is to use the old platform files, where you can specify the base number of a gpio_chip.
DT is actually probably not such a bad place to provide consistency in GPIO numbering. It has a global vision of the system layout, including all GPIO controllers and the number of GPIOs they include, and thus can make informed decisions. It provides a consistent result regardless of probe order. And allowing it to assign GPIO bases to controllers will free us from the nonsensical dependency of some arbitrary upper-bound for GPIO numbers that ARCH_NR_GPIOS imposes on us. Also about ARCH_NR_GPIOS, the plan is to eventually remove it since we don't need it anymore after the removal of the global gpio_descs array. This will again interfere with the numbering of GPIO chips that do not have a base number provided.
Note that I don't really like this, either - but the problem is the GPIO integer interface. Until everyone has upgraded to gpiod and we have a replacement for the current sysfs interface (this will take a while) we have to cope with this. This issue has been bothering users for years, so this time I'd like to try and solve it the less ugly way. If there is a better solution, of course I'm all for it.
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
Quoted 41 lines · On Friday 12 December 2014 22:05:37 Alexandre Courbot wrote:
Quoted 10 lines · Arnd Bergmann
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt line 17
Quoted 5 lines · On Thursday 11 December 2014 16:05:04 Ray Jui wrote:
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt new file +4
-0+ +- linux,gpio-base: + Base GPIO number of this controller +We've NAK'ed properties like this multiple times before, and it doesn't get any better this time. What are you trying to achieve here?
I am to blame for suggesting using this property to Ray, and I am fully aware that this has been rejected before, but look at what people came with recently to palliate the lack of control over the GPIO number space for DT platforms:
http://www.spinics.net/lists/arm-kernel/msg384847.html
https://lkml.org/lkml/2014/12/10/133Right now GPIO numbering for platforms using DT is a very inconsistent process, subject to change by the simple action of adjusting the value of
ARCH_NR_GPIOS(which we did recently, btw), adding a new GPIO controller, or changing the probe order of devices. For users of the integer or sysfs interfaces, this results in GPIO numbers that change, and drivers and/or user-space programs that behave incorrectly. Ironically, the only way to have consistent numbers is to use the old platform files, where you can specify the base number of agpio_chip.DT is actually probably not such a bad place to provide consistency in GPIO numbering. It has a global vision of the system layout, including all GPIO controllers and the number of GPIOs they include, and thus can make informed decisions. It provides a consistent result regardless of probe order. And allowing it to assign GPIO bases to controllers will free us from the nonsensical dependency of some arbitrary upper-bound for GPIO numbers that
ARCH_NR_GPIOSimposes on us. Also aboutARCH_NR_GPIOS, the plan is to eventually remove it since we don't need it anymore after the removal of the globalgpio_descsarray. This will again interfere with the numbering of GPIO chips that do not have a base number provided.
Quoted 6 lines
Note that I don't really like this, either - but the problem is the GPIO integer interface. Until everyone has upgraded to gpiod and we have a replacement for the current sysfs interface (this will take a while) we have to cope with this. This issue has been bothering users for years, so this time I'd like to try and solve it the less ugly way. If there is a better solution, of course I'm all for it.
I think the scheme will fail if you ever get gpio controllers that are not part of the DT: We have hotpluggable devices (PCI, USB, ...) that are not represented in DT and that may also provide GPIOs for internal uses.
The current state of affairs is definitely problematic, but defining the GPIO numbers in DT properties would only be a relative improvement, not a solution, and I fear it would make it harder to change the kernel to remove the gpio numbers eventually.
I wonder if we could instead come up with an approach that completely randomizes the gpio numbers (as a compile-time option) to find any places that still rely on specific numbers.
Arnd
Ray Jui
maintainerRe: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
Quoted 59 lines · Arnd Bergmann
Quoted 41 lines · On Friday 12 December 2014 22:05:37 Alexandre Courbot wrote:
Quoted 10 lines · Arnd Bergmann
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt line 17
Quoted 5 lines · On Thursday 11 December 2014 16:05:04 Ray Jui wrote:
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt new file +4
-0+ +- linux,gpio-base: + Base GPIO number of this controller +We've NAK'ed properties like this multiple times before, and it doesn't get any better this time. What are you trying to achieve here?
I am to blame for suggesting using this property to Ray, and I am fully aware that this has been rejected before, but look at what people came with recently to palliate the lack of control over the GPIO number space for DT platforms:
http://www.spinics.net/lists/arm-kernel/msg384847.html
https://lkml.org/lkml/2014/12/10/133Right now GPIO numbering for platforms using DT is a very inconsistent process, subject to change by the simple action of adjusting the value of
ARCH_NR_GPIOS(which we did recently, btw), adding a new GPIO controller, or changing the probe order of devices. For users of the integer or sysfs interfaces, this results in GPIO numbers that change, and drivers and/or user-space programs that behave incorrectly. Ironically, the only way to have consistent numbers is to use the old platform files, where you can specify the base number of agpio_chip.DT is actually probably not such a bad place to provide consistency in GPIO numbering. It has a global vision of the system layout, including all GPIO controllers and the number of GPIOs they include, and thus can make informed decisions. It provides a consistent result regardless of probe order. And allowing it to assign GPIO bases to controllers will free us from the nonsensical dependency of some arbitrary upper-bound for GPIO numbers that
ARCH_NR_GPIOSimposes on us. Also aboutARCH_NR_GPIOS, the plan is to eventually remove it since we don't need it anymore after the removal of the globalgpio_descsarray. This will again interfere with the numbering of GPIO chips that do not have a base number provided.Quoted 6 lines
Note that I don't really like this, either - but the problem is the GPIO integer interface. Until everyone has upgraded to gpiod and we have a replacement for the current sysfs interface (this will take a while) we have to cope with this. This issue has been bothering users for years, so this time I'd like to try and solve it the less ugly way. If there is a better solution, of course I'm all for it.
I think the scheme will fail if you ever get gpio controllers that are not part of the DT: We have hotpluggable devices (PCI, USB, ...) that are not represented in DT and that may also provide GPIOs for internal uses.
The current state of affairs is definitely problematic, but defining the GPIO numbers in DT properties would only be a relative improvement, not a solution, and I fear it would make it harder to change the kernel to remove the gpio numbers eventually.
Quoted 6 lines
I wonder if we could instead come up with an approach that completely randomizes the gpio numbers (as a compile-time option) to find any places that still rely on specific numbers.
Arnd
Okay, if people think defining the GPIO base number in DT properties as a temporary, transient solution is not acceptable, I can switch the driver to use dynamic GPIO number allocation (by setting gpio base to a negative number and let gpiochip_add find a usable base number).
Like I said previously, dynamic GPIO allocation works fine in the kernel, as long as all of our GPIO clients in the kernel use gpiod based API, which is what we will enforce going forward. The only problem is with some of our customers who use GPIO through sysfs and expect fixed global GPIO numbers. Thinking about this more, it's probably not that difficult to add a script for those customers to convert/map the GPIO numbers based on readings parsed from sysfs, so I guess that's fine.
I'll submit v6 patchset with DT property "linux,gpio-base" removed.
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
Quoted 9 lines · On Monday 15 December 2014 13:35:47 Ray Jui wrote:
Like I said previously, dynamic GPIO allocation works fine in the kernel, as long as all of our GPIO clients in the kernel use gpiod based API, which is what we will enforce going forward. The only problem is with some of our customers who use GPIO through sysfs and expect fixed global GPIO numbers. Thinking about this more, it's probably not that difficult to add a script for those customers to convert/map the GPIO numbers based on readings parsed from sysfs, so I guess that's fine.
I think we discussed the user space interface a number of times in the past, but I forgot the outcome. Either there is already a way to name gpio lines uniquely in sysfs, or there should be one.
Can you reach the gpio interfaces using /sys/devices/0001234.bus/1234566.gpiocontroller/...?
Arnd
Ray Jui
maintainerRe: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
Quoted 11 lines · Arnd Bergmann
Quoted 9 lines · On Monday 15 December 2014 13:35:47 Ray Jui wrote:
Like I said previously, dynamic GPIO allocation works fine in the kernel, as long as all of our GPIO clients in the kernel use gpiod based API, which is what we will enforce going forward. The only problem is with some of our customers who use GPIO through sysfs and expect fixed global GPIO numbers. Thinking about this more, it's probably not that difficult to add a script for those customers to convert/map the GPIO numbers based on readings parsed from sysfs, so I guess that's fine.
Quoted 9 lines
I think we discussed the user space interface a number of times in the past, but I forgot the outcome. Either there is already a way to name gpio lines uniquely in sysfs, or there should be one.
Can you reach the gpio interfaces using
/sys/devices/0001234.bus/1234566.gpiocontroller/...?Arnd
We use entries under /sys/class/gpio/ to control GPIOs. All base, label, and ngpio info specific to a GPIO controller can be found there.
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
In reply to Arnd BergmannQuoted 11 lines · Arnd Bergmann
Quoted 9 lines · On Monday 15 December 2014 13:35:47 Ray Jui wrote:
Like I said previously, dynamic GPIO allocation works fine in the kernel, as long as all of our GPIO clients in the kernel use gpiod based API, which is what we will enforce going forward. The only problem is with some of our customers who use GPIO through sysfs and expect fixed global GPIO numbers. Thinking about this more, it's probably not that difficult to add a script for those customers to convert/map the GPIO numbers based on readings parsed from sysfs, so I guess that's fine.
Quoted 6 lines
I think we discussed the user space interface a number of times in the past, but I forgot the outcome. Either there is already a way to name gpio lines uniquely in sysfs, or there should be one.
Can you reach the gpio interfaces using
/sys/devices/0001234.bus/1234566.gpiocontroller/...?
No, but it seems like this is exactly the solution we need. We could have an "export" node there that takes a relative GPIO number and exports it under /sys/devices/0001234.bus/1234566.gpiocontroller/exported/ the same way the current sysfs exporter does. Then for convenience we could also allow exported GPIOs to take names to be used under the shorter /sys/class/gpio/ (named GPIOs is another request we pushed back many times but that keeps coming).
Let's see if I can come with a patch. That would at least give us something to reply to the many people that hit this issue.
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
In reply to Arnd BergmannQuoted 11 lines · Arnd Bergmann
Quoted 9 lines · On Monday 15 December 2014 13:35:47 Ray Jui wrote:
Like I said previously, dynamic GPIO allocation works fine in the kernel, as long as all of our GPIO clients in the kernel use gpiod based API, which is what we will enforce going forward. The only problem is with some of our customers who use GPIO through sysfs and expect fixed global GPIO numbers. Thinking about this more, it's probably not that difficult to add a script for those customers to convert/map the GPIO numbers based on readings parsed from sysfs, so I guess that's fine.
Quoted 4 lines
I think we discussed the user space interface a number of times in the past, but I forgot the outcome. Either there is already a way to name gpio lines uniquely in sysfs, or there should be one.
There is one. The struct gpio_chip contains a .names field with strings giving names to the GPIOs on the chip.
This field does not have standardized DT bindings or anything but should be used.
Overall the sysfs interface is an abomination for relying on the notoriously unstable GPIO numberspace and other things. It was merged when the subsystem lacked a maintainer.
Yours,
Linus Walleij
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
In reply to Arnd BergmannQuoted 54 lines · Arnd Bergmann
Quoted 41 lines · On Friday 12 December 2014 22:05:37 Alexandre Courbot wrote:
Quoted 10 lines · Arnd Bergmann
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt line 17
Quoted 5 lines · On Thursday 11 December 2014 16:05:04 Ray Jui wrote:
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt new file +4
-0+ +- linux,gpio-base: + Base GPIO number of this controller +We've NAK'ed properties like this multiple times before, and it doesn't get any better this time. What are you trying to achieve here?
I am to blame for suggesting using this property to Ray, and I am fully aware that this has been rejected before, but look at what people came with recently to palliate the lack of control over the GPIO number space for DT platforms:
http://www.spinics.net/lists/arm-kernel/msg384847.html
https://lkml.org/lkml/2014/12/10/133Right now GPIO numbering for platforms using DT is a very inconsistent process, subject to change by the simple action of adjusting the value of
ARCH_NR_GPIOS(which we did recently, btw), adding a new GPIO controller, or changing the probe order of devices. For users of the integer or sysfs interfaces, this results in GPIO numbers that change, and drivers and/or user-space programs that behave incorrectly. Ironically, the only way to have consistent numbers is to use the old platform files, where you can specify the base number of agpio_chip.DT is actually probably not such a bad place to provide consistency in GPIO numbering. It has a global vision of the system layout, including all GPIO controllers and the number of GPIOs they include, and thus can make informed decisions. It provides a consistent result regardless of probe order. And allowing it to assign GPIO bases to controllers will free us from the nonsensical dependency of some arbitrary upper-bound for GPIO numbers that
ARCH_NR_GPIOSimposes on us. Also aboutARCH_NR_GPIOS, the plan is to eventually remove it since we don't need it anymore after the removal of the globalgpio_descsarray. This will again interfere with the numbering of GPIO chips that do not have a base number provided.Quoted 6 lines
Note that I don't really like this, either - but the problem is the GPIO integer interface. Until everyone has upgraded to gpiod and we have a replacement for the current sysfs interface (this will take a while) we have to cope with this. This issue has been bothering users for years, so this time I'd like to try and solve it the less ugly way. If there is a better solution, of course I'm all for it.
I think the scheme will fail if you ever get gpio controllers that are not part of the DT: We have hotpluggable devices (PCI, USB, ...) that are not represented in DT and that may also provide GPIOs for internal uses.
Quoted 4 lines
The current state of affairs is definitely problematic, but defining the GPIO numbers in DT properties would only be a relative improvement, not a solution, and I fear it would make it harder to change the kernel to remove the gpio numbers eventually.
You are absolutely right that this would be only a partial solution. However this is a situation where there is no absolute fix (besides dropping the GPIO numbers completely) and the relief this property would brings makes it up for its shortcomings IMHO.
Quoted 3 lines
I wonder if we could instead come up with an approach that completely randomizes the gpio numbers (as a compile-time option) to find any places that still rely on specific numbers.
A.k.a. Linus and Alex' hate mail generator. :P
Actually we are not that far from being able to do completely without any GPIO number, and maybe that's what we should aim for. I think the only remaining offender is the sysfs interface. If we could reach GPIO controllers through a fixed path and just export their GPIOs there, I believe we would have fixed the whole issue.
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
Quoted 6 lines · On Wednesday 17 December 2014 11:45:01 Alexandre Courbot wrote:
Actually we are not that far from being able to do completely without any GPIO number, and maybe that's what we should aim for. I think the only remaining offender is the sysfs interface. If we could reach GPIO controllers through a fixed path and just export their GPIOs there, I believe we would have fixed the whole issue.
What about the hundreds of board files and device drivers that still reference hardcoded gpio numbers? The problem seems mostly solved for anything that uses DT, but there are some architectures and a number of ARM platforms that don't use DT and probably never will.
I would assume they could all be changed to use gpiod_lookup tables, but that's a lot of work.
Arnd
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
Quoted 8 lines · Arnd Bergmann
Quoted 6 lines · On Wednesday 17 December 2014 11:45:01 Alexandre Courbot wrote:
Actually we are not that far from being able to do completely without any GPIO number, and maybe that's what we should aim for. I think the only remaining offender is the sysfs interface. If we could reach GPIO controllers through a fixed path and just export their GPIOs there, I believe we would have fixed the whole issue.
Quoted 7 lines
What about the hundreds of board files and device drivers that still reference hardcoded gpio numbers? The problem seems mostly solved for anything that uses DT, but there are some architectures and a number of ARM platforms that don't use DT and probably never will.
I would assume they could all be changed to use
gpiod_lookuptables, but that's a lot of work.
Indeed, that's not something to expect, as I replied to Russell. Sorry about the confusion.
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
In reply to Alexandre CourbotQuoted 3 lines · Alexandre Courbot
Actually we are not that far from being able to do completely without any GPIO number, and maybe that's what we should aim for. I think the only remaining offender is the sysfs interface.
And that is a user API, and there's lots of users of it (eg, on Raspberry Pi platforms.) So changing it isn't going to be easy - I'd say that it's impractical.
What you're suggesting would be like re-numbering Linux syscalls.
Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up according to speedtest.net.
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
Quoted 10 lines · Russell King - ARM Linux
Quoted 3 lines · Alexandre Courbot
Actually we are not that far from being able to do completely without any GPIO number, and maybe that's what we should aim for. I think the only remaining offender is the sysfs interface.
And that is a user API, and there's lots of users of it (eg, on Raspberry Pi platforms.) So changing it isn't going to be easy - I'd say that it's impractical.
What you're suggesting would be like re-numbering Linux syscalls.
Uh, I expressed myself poorly. What I intended to say is that once we have a sysfs alternative that does not rely on GPIO numbers (and thus have the same feature coverage as the integer interface), we can require new platforms to exclusively rely on gpiod/sysfs2, and encourage older users to switch to it if they have an issue with the way integers are handled or need one of the new features.
I don't foresee that we will ever be able to retire the integer interface, however I would like to be able to say "your problem will be solved if you switch to gpiod" instead of having to juggle with potentially conflicting integer range requirements from different platforms. Right now the only thing that prevents us to say that is the lack of a consistent sysfs interface.
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
In reply to Russell King - ARM LinuxQuoted 10 lines · Russell King - ARM Linux
Quoted 3 lines · Alexandre Courbot
Actually we are not that far from being able to do completely without any GPIO number, and maybe that's what we should aim for. I think the only remaining offender is the sysfs interface.
And that is a user API, and there's lots of users of it (eg, on Raspberry Pi platforms.) So changing it isn't going to be easy - I'd say that it's impractical.
What you're suggesting would be like re-numbering Linux syscalls.
The problem is that right now if we set the .base of a gpio_chip to -1 for dynamic allocation of GPIO numbers and we have more than one GPIO chip in the system, the numbers basically depend on probe order, and may theoretically even differ between two boots.
So in these cases preserving the ABI means preserving the unpredictability of these assigned numbers or something.
For the old usecases with a single GPIO controller and a fixed base offset of e.g. 0 (which I suspect was implicit in the initial design of the subsystem) things work fine as always, it's these new dynamic use cases that destabilize the ABI.
Yours,
Linus Walleij
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
Quoted 18 lines · Linus Walleij
Quoted 10 lines · Russell King - ARM Linux
Quoted 3 lines · Alexandre Courbot
Actually we are not that far from being able to do completely without any GPIO number, and maybe that's what we should aim for. I think the only remaining offender is the sysfs interface.
And that is a user API, and there's lots of users of it (eg, on Raspberry Pi platforms.) So changing it isn't going to be easy - I'd say that it's impractical.
What you're suggesting would be like re-numbering Linux syscalls.
The problem is that right now if we set the .base of a
gpio_chipto -1 for dynamic allocation of GPIO numbers and we have more than one GPIO chip in the system, the numbers basically depend on probe order, and may theoretically even differ between two boots.
Quoted 7 lines
So in these cases preserving the ABI means preserving the unpredictability of these assigned numbers or something.
For the old usecases with a single GPIO controller and a fixed base offset of e.g. 0 (which I suspect was implicit in the initial design of the subsystem) things work fine as always, it's these new dynamic use cases that destabilize the ABI.
Since GPIOs are exported through sysfs into userland by GPIO number, and we know that there are users of it (see
https://github.com/pilight/wiringX) which hard encode GPIO numbers, so this is *really* something that we as kernel developers can't change without breaking such users.
So, what I'm saying is be very careful about moving to a fully dynamic space: you could end up breaking userspace if you do.
Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up according to speedtest.net.
Re: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
Quoted 27 lines · Russell King - ARM Linux
Quoted 18 lines · Linus Walleij
Quoted 10 lines · Russell King - ARM Linux
Quoted 3 lines · Alexandre Courbot
Actually we are not that far from being able to do completely without any GPIO number, and maybe that's what we should aim for. I think the only remaining offender is the sysfs interface.
And that is a user API, and there's lots of users of it (eg, on Raspberry Pi platforms.) So changing it isn't going to be easy - I'd say that it's impractical.
What you're suggesting would be like re-numbering Linux syscalls.
The problem is that right now if we set the .base of a
gpio_chipto -1 for dynamic allocation of GPIO numbers and we have more than one GPIO chip in the system, the numbers basically depend on probe order, and may theoretically even differ between two boots.Quoted 7 lines
So in these cases preserving the ABI means preserving the unpredictability of these assigned numbers or something.
For the old usecases with a single GPIO controller and a fixed base offset of e.g. 0 (which I suspect was implicit in the initial design of the subsystem) things work fine as always, it's these new dynamic use cases that destabilize the ABI.
Quoted 5 lines
Since GPIOs are exported through sysfs into userland by GPIO number, and we know that there are users of it (see
https://github.com/pilight/wiringX) which hard encode GPIO numbers, so this is *really* something that we as kernel developers can't change without breaking such users.
I agree.
In some other thread I came up with the idea that if we add enumerated aliases for the GPIO controllers in the device tree (so that each can be assigned a sequence number, like we do on the PL011 ttys) we can assign them numbers starting from 0.
The only reason that dynamic GPIO start from some random high offset is that the on-chip GPIOs are assumed to be present at offset 0+, so this is done so that the dynamic controllers avoid colliding with them. (At least that is how I understand it.) So on a fully DT-enabled system assigning numbers starting from 0 should be kind of default.
Yours,
Linus Walleij
Ray Jui
maintainerRe: [PATCH v5 1/3] gpio: Cygnus: define Broadcom Cygnus GPIO binding
In reply to Alexandre CourbotQuoted 41 lines · Alexandre Courbot
Quoted 10 lines · Arnd Bergmann
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt line 17
Quoted 5 lines · On Thursday 11 December 2014 16:05:04 Ray Jui wrote:
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt new file +4
-0+ +- linux,gpio-base: + Base GPIO number of this controller +We've NAK'ed properties like this multiple times before, and it doesn't get any better this time. What are you trying to achieve here?
I am to blame for suggesting using this property to Ray, and I am fully aware that this has been rejected before, but look at what people came with recently to palliate the lack of control over the GPIO number space for DT platforms:
http://www.spinics.net/lists/arm-kernel/msg384847.html
https://lkml.org/lkml/2014/12/10/133Right now GPIO numbering for platforms using DT is a very inconsistent process, subject to change by the simple action of adjusting the value of
ARCH_NR_GPIOS(which we did recently, btw), adding a new GPIO controller, or changing the probe order of devices. For users of the integer or sysfs interfaces, this results in GPIO numbers that change, and drivers and/or user-space programs that behave incorrectly. Ironically, the only way to have consistent numbers is to use the old platform files, where you can specify the base number of agpio_chip.DT is actually probably not such a bad place to provide consistency in GPIO numbering. It has a global vision of the system layout, including all GPIO controllers and the number of GPIOs they include, and thus can make informed decisions. It provides a consistent result regardless of probe order. And allowing it to assign GPIO bases to controllers will free us from the nonsensical dependency of some arbitrary upper-bound for GPIO numbers that
ARCH_NR_GPIOSimposes on us. Also aboutARCH_NR_GPIOS, the plan is to eventually remove it since we don't need it anymore after the removal of the globalgpio_descsarray. This will again interfere with the numbering of GPIO chips that do not have a base number provided.
Quoted 7 lines
Note that I don't really like this, either - but the problem is the GPIO integer interface. Until everyone has upgraded to gpiod and we have a replacement for the current sysfs interface (this will take a while) we have to cope with this. This issue has been bothering users for years, so this time I'd like to try and solve it the less ugly way. If there is a better solution, of course I'm all for it.
Agreed.
Since we are just starting to upstream all of our drivers for iProc/Cygnus, enforcing all of our new drivers to use the gpiod interface is not an issue and is something that should be done.
Our current issue is really on the sysfs interface, as I mentioned earlier, a lot of our customers use the sysfs interface for GPIO access. Until the sysfs interface issue is resolved, we sort of need a way to maintain the GPIO base between different GPIO controllers.
Ray Jui
maintainerPATCH v5 2/3 gpio: Cygnus: add GPIO driver
In reply to Ray JuiThis GPIO driver supports all 3 GPIO controllers in the Broadcom Cygnus SoC. The 3 GPIO controllers are 1) the ASIU GPIO controller, 2) the chipCommonG GPIO controller, and 3) the ALWAYS-ON GPIO controller
--- drivers/gpio/Kconfig | 12 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-bcm-cygnus.c | 613 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 626 insertions(+) create mode 100644 drivers/gpio/gpio-bcm-cygnus.c
drivers/gpio/Kconfig +12 -0
@@ -126,6 +126,18 @@ config GPIO_74XX_MMIO 8 bits: 74244 (Input), 74273 (Output) 16 bits: 741624 (Input), 7416374 (Output) +config GPIO_BCM_CYGNUS + bool "Broadcom Cygnus GPIO support" + depends on ARCH_BCM_CYGNUS && OF_GPIO + default y + help + Say yes here to turn on GPIO support for Broadcom Cygnus SoC + + The Broadcom Cygnus SoC has 3 GPIO controllers including the ASIU + GPIO controller (ASIU), the chipCommonG GPIO controller (CCM), and + the always-ON GPIO controller (CRMU). All 3 GPIO controllers are + supported by this driver + config GPIO_CLPS711X tristate "CLPS711X GPIO support" depends on ARCH_CLPS711X || COMPILE_TEST
drivers/gpio/Makefile +1 -0
@@ -19,6 +19,7 @@ obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o +obj-$(CONFIG_GPIO_BCM_CYGNUS) += gpio-bcm-cygnus.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
drivers/gpio/gpio-bcm-cygnus.c new file +613 -0
613 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v5 3/3 ARM: dts: enable GPIO for Broadcom Cygnus
In reply to Ray JuiThis enables all 3 GPIO controllers including the ASIU GPIO, the chipcommonG GPIO, and the ALWAYS-ON GPIO, for Broadcom Cygnus SoC
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +33 -0
@@ -54,6 +54,39 @@ /include/ "bcm-cygnus-clock.dtsi" + gpio_ccm: gpio@1800a000 { + compatible = "brcm,cygnus-gpio"; + reg = <0x1800a000 0x50>, + <0x0301d164 0x20>; + ngpios = <24>; + linux,gpio-base = <0>; + #gpio-cells = <2>; + gpio-controller; + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + }; + + gpio_asiu: gpio@180a5000 { + compatible = "brcm,cygnus-gpio"; + reg = <0x180a5000 0x668>; + ngpios = <122>; + linux,gpio-base = <24>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; + }; + + gpio_crmu: gpio@03024800 { + compatible = "brcm,cygnus-gpio"; + reg = <0x03024800 0x50>; + ngpios = <6>; + linux,gpio-base = <146>; + #gpio-cells = <2>; + gpio-controller; + no-drv-strength; + }; + amba { #address-cells = <1>; #size-cells = <1>;
Signature · 1 line
1.7.9.5
Ray Jui
maintainerv2 cover Add PCIe support to Broadcom iProc
In reply to a message not in the archiveThis patchset contains the initial PCIe support for Broadcom iProc family of SoCs. This driver has been validated with Cygnus and NSP and is expected to work on other iProc family of SoCs that deploy the same PCIe controller
Changes from v1:
- Add standard PCI interrupt DT properties "#interrupt-cells", "interrupt-map-mask" and "interrupt-map" so legacy INTx interrupts can be supported by using standard PCI OF IRQ parsing function
- Get rid of custom IRQ mapping function in the driver. Use of_irq_parse_and_map_pci instead
Ray Jui (4):
pci: iProc: define Broadcom iProc PCIe binding
PCI: iproc: Add Broadcom iProc PCIe driver
ARM: mach-bcm: Enable PCIe support for iProc
ARM: dts: enable PCIe for Broadcom Cygnus
.../devicetree/bindings/pci/brcm,iproc-pcie.txt | 74 ++ arch/arm/boot/dts/bcm-cygnus.dtsi | 52 ++ arch/arm/boot/dts/bcm958300k.dts | 8 + arch/arm/mach-bcm/Kconfig | 1 + drivers/pci/host/Kconfig | 9 + drivers/pci/host/Makefile | 1 + drivers/pci/host/pcie-iproc.c | 888 ++++++++++++++++++++ 7 files changed, 1033 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt create mode 100644 drivers/pci/host/pcie-iproc.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v2 1/4 pci: iProc: define Broadcom iProc PCIe binding
Document the PCIe device tree binding for Broadcom iProc family of SoCs
--- .../devicetree/bindings/pci/brcm,iproc-pcie.txt | 74 ++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +74 -0
@@ -0,0 +1,74 @@ +* Broadcom iProc PCIe controller + +Required properties: +- compatible: Must be "brcm,iproc-pcie" +- reg: base address and length of the PCIe controller and the MDIO interface + that controls the PCIe PHY +- #interrupt-cells: set to <1> +- interrupts: interrupt IDs +- interrupt-map-mask and interrupt-map, standard PCI properties to define the + mapping of the PCIe interface to interrupt numbers +- bus-range: PCI bus numbers covered +- #address-cells: set to <3> +- #size-cells: set to <2> +- device_type: set to "pci" +- ranges: ranges for the PCI memory and I/O regions +- phy-addr: MDC/MDIO adddress of the PCIe PHY +- have-msi-inten-reg: Required for legacy iProc PCIe controllers that need the + MSI interrupt enable register to be set explicitly + +The Broadcom iProc PCie driver adapts the multi-domain structure, i.e., each +interface has its own domain and therefore has its own device node +Example: + +SoC specific DT Entry: + + pcie0: pcie@18012000 { + compatible = "brcm,iproc-pcie"; + reg = <0x18012000 0x1000>, + <0x18002000 0x1000>; + + #interrupt-cells = <1>; + interrupts = <GIC_SPI 96 IRQ_TYPE_NONE>, + <GIC_SPI 97 IRQ_TYPE_NONE>, + <GIC_SPI 98 IRQ_TYPE_NONE>, + <GIC_SPI 99 IRQ_TYPE_NONE>, + <GIC_SPI 100 IRQ_TYPE_NONE>, + <GIC_SPI 101 IRQ_TYPE_NONE>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>; + + bus-range = <0x00 0xFF>; + + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x28000000 0 0x00010000 /* downstream I/O */ + 0x82000000 0 0x20000000 0x20000000 0 0x04000000>; /* non-prefetchable memory */ + phy-addr = <5>; + }; + + pcie1: pcie@18013000 { + compatible = "brcm,iproc-pcie"; + reg = <0x18013000 0x1000>, + <0x18002000 0x1000>; + + #interrupt-cells = <1>; + interrupts = <GIC_SPI 102 IRQ_TYPE_NONE>, + <GIC_SPI 103 IRQ_TYPE_NONE>, + <GIC_SPI 104 IRQ_TYPE_NONE>, + <GIC_SPI 105 IRQ_TYPE_NONE>, + <GIC_SPI 106 IRQ_TYPE_NONE>, + <GIC_SPI 107 IRQ_TYPE_NONE>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 106 IRQ_TYPE_NONE>; + + bus-range = <0x00 0xFF>; + + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x48000000 0 0x00010000 /* downstream I/O */ + 0x82000000 0 0x40000000 0x40000000 0 0x04000000>; /* non-prefetchable memory */ + phy-addr = <6>; + };
Signature · 1 line
1.7.9.5
Re: [PATCH v2 1/4] pci: iProc: define Broadcom iProc PCIe binding
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 8
Quoted 12 lines · On Thursday 11 December 2014 18:36:54 Ray Jui wrote:
index 0000000..040bc0f
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +8
-0@@ -0,0 +1,74 @@ +* Broadcom iProc PCIe controller + +Required properties: +- compatible: Must be "brcm,iproc-pcie" +- reg: base address and length of the PCIe controller and the MDIO interface + that controls the PCIe PHY +- #interrupt-cells: set to <1> +- interrupts: interrupt IDs
How many, and what are they?
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 16
Quoted 8 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +8
-0+- interrupt-map-mask and interrupt-map, standard PCI properties to define the + mapping of the PCIe interface to interrupt numbers +- bus-range: PCI bus numbers covered +- #address-cells: set to <3> +- #size-cells: set to <2> +- device_type: set to "pci" +- ranges: ranges for the PCI memory and I/O regions +- phy-addr: MDC/MDIO adddress of the PCIe PHY
It looks like the phy controller is separate from the PCI controller, and you even list the same register range for both PHYs. Better make that a separate driver and put the phy address into the "phys" reference.
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 29
Quoted 13 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +13
-0+- have-msi-inten-reg: Required for legacy iProc PCIe controllers that need the + MSI interrupt enable register to be set explicitly + +The Broadcom iProc PCie driver adapts the multi-domain structure, i.e., each +interface has its own domain and therefore has its own device node +Example: + +SoC specific DT Entry: + + pcie0: pcie at 18012000 { + compatible = "brcm,iproc-pcie"; + reg = <0x18012000 0x1000>, + <0x18002000 0x1000>;
I guess the addresses should be relative to the BCMA bus, and this node get moved under that. Please see Hauke's patch series, we've discussed this in great length already.
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 39
Quoted 12 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +9
-0+ #interrupt-cells = <1>; + interrupts = <GIC_SPI 96 IRQ_TYPE_NONE>, + <GIC_SPI 97 IRQ_TYPE_NONE>, + <GIC_SPI 98 IRQ_TYPE_NONE>, + <GIC_SPI 99 IRQ_TYPE_NONE>, + <GIC_SPI 100 IRQ_TYPE_NONE>, + <GIC_SPI 101 IRQ_TYPE_NONE>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>;
This interrupt is also listed in the "interrupts" above, which is probably a mistake, unless the IRQ line is shared between all PCI devices and the PCI host itself.
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 49
Quoted 10 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +9
-0+ bus-range = <0x00 0xFF>; + + #address-cells = >; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x28000000 0 0x00010000 /* downstream I/O */ + 0x82000000 0 0x20000000 0x20000000 0 0x04000000>; /* non-prefetchable memory */ + phy-addr = <5>; + };
Arnd
Ray Jui
maintainerRe: [PATCH v2 1/4] pci: iProc: define Broadcom iProc PCIe binding
Quoted 16 lines · Arnd Bergmann
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 8
Quoted 12 lines · On Thursday 11 December 2014 18:36:54 Ray Jui wrote:
index 0000000..040bc0f
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +8
-0@@ -0,0 +1,74 @@ +* Broadcom iProc PCIe controller + +Required properties: +- compatible: Must be "brcm,iproc-pcie" +- reg: base address and length of the PCIe controller and the MDIO interface + that controls the PCIe PHY +- #interrupt-cells: set to <1> +- interrupts: interrupt IDsHow many, and what are they?
Different iProc SoCs might have different number of interrupts. I'll elaborate more on the next patch.
Quoted 9 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 16
Quoted 8 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +8
-0+- interrupt-map-mask and interrupt-map, standard PCI properties to define the + mapping of the PCIe interface to interrupt numbers +- bus-range: PCI bus numbers covered +- #address-cells: set to <3> +- #size-cells: set to <2> +- device_type: set to "pci" +- ranges: ranges for the PCI memory and I/O regions +- phy-addr: MDC/MDIO adddress of the PCIe PHY
Quoted 4 lines
It looks like the phy controller is separate from the PCI controller, and you even list the same register range for both PHYs. Better make that a separate driver and put the phy address into the "phys" reference.
Okay. In this case, I need to create a separate PHY driver under the drivers/phy directory and have the PCIe host driver reference it through the standard PHY API.
Quoted 9 lines
Quoted 9 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +9
-0+- have-msi-inten-reg: Required for legacy iProc PCIe controllers that need the + MSI interrupt enable register to be set explicitly + +The Broadcom iProc PCie driver adapts the multi-domain structure, i.e., each +interface has its own domain and therefore has its own device node +Example: + +SoC specific DT Entry: +
Quoted 9 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 29
Quoted 4 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +4
-0+ pcie0: pcie at 18012000 { + compatible = "brcm,iproc-pcie"; + reg = <0x18012000 0x1000>, + <0x18002000 0x1000>;I guess the addresses should be relative to the BCMA bus, and this node get moved under that. Please see Hauke's patch series, we've discussed this in great length already.
As Arend van Spriel pointed out in the previous discussion:
BCMA core is the bus driver for discoverable ARM AXI interconnect. Apart from that it also provides drivers for some cores. For the chips to be discoverable it needs additional IP logic.
Not all iProc family of SoCs have the additional IP logic and for those which don't, they cannot use the BCMA bus.
Quoted 10 lines
Quoted 7 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +7
-0+ #interrupt-cells = <1>; + interrupts = <GIC_SPI 96 IRQ_TYPE_NONE>, + <GIC_SPI 97 IRQ_TYPE_NONE>, + <GIC_SPI 98 IRQ_TYPE_NONE>, + <GIC_SPI 99 IRQ_TYPE_NONE>, + <GIC_SPI 100 IRQ_TYPE_NONE>, + <GIC_SPI 101 IRQ_TYPE_NONE>;
Quoted 7 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 39
Quoted 2 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +2
-0+ interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>;This interrupt is also listed in the "interrupts" above, which is probably a mistake, unless the IRQ line is shared between all PCI devices and the PCI host itself.
interrupts are for MSI interrupt support and interrupt-map is for legacy INTx support. To my best knowledge, MSI and INTx cannot be used at the same time. "nvidia,tegra20-pcie.txt" and "rcar-pci.txt" have similar configurations.
Quoted 13 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 49
Quoted 10 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +9
-0+ bus-range = <0x00 0xFF>; + + #address-cells = >; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x28000000 0 0x00010000 /* downstream I/O */ + 0x82000000 0 0x20000000 0x20000000 0 0x04000000>; /* non-prefetchable memory */ + phy-addr = <5>; + };Arnd
Re: [PATCH v2 1/4] pci: iProc: define Broadcom iProc PCIe binding
Quoted 18 lines · On Friday 12 December 2014 08:53:44 Ray Jui wrote:
Quoted 16 lines · Arnd Bergmann
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 8
Quoted 12 lines · On Thursday 11 December 2014 18:36:54 Ray Jui wrote:
index 0000000..040bc0f
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +8
-0@@ -0,0 +1,74 @@ +* Broadcom iProc PCIe controller + +Required properties: +- compatible: Must be "brcm,iproc-pcie" +- reg: base address and length of the PCIe controller and the MDIO interface + that controls the PCIe PHY +- #interrupt-cells: set to <1> +- interrupts: interrupt IDsHow many, and what are they?
Quoted 2 lines
Different iProc SoCs might have different number of interrupts. I'll elaborate more on the next patch.
Ok.
Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +8
-0+- interrupt-map-mask and interrupt-map, standard PCI properties to define the + mapping of the PCIe interface to interrupt numbers +- bus-range: PCI bus numbers covered +- #address-cells: set to <3> +- #size-cells: set to <2> +- device_type: set to "pci" +- ranges: ranges for the PCI memory and I/O regions +- phy-addr: MDC/MDIO adddress of the PCIe PHY
Quoted 7 lines
Quoted 4 lines
It looks like the phy controller is separate from the PCI controller, and you even list the same register range for both PHYs. Better make that a separate driver and put the phy address into the "phys" reference.
Okay. In this case, I need to create a separate PHY driver under the
drivers/phydirectory and have the PCIe host driver reference it through the standard PHY API.
Yes, that is what I meant. In particular, that has the advantage of letting you reuse the two drivers separately if some new SoC comes up that uses one but not the other. A lot of PHY implementations can support multiple protocols (e.g. pcie and usb3), but I don't know if yours does.
Quoted 19 lines
Quoted 9 lines
Quoted 9 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +9
-0+- have-msi-inten-reg: Required for legacy iProc PCIe controllers that need the + MSI interrupt enable register to be set explicitly + +The Broadcom iProc PCie driver adapts the multi-domain structure, i.e., each +interface has its own domain and therefore has its own device node +Example: + +SoC specific DT Entry: +Quoted 9 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 29
Quoted 4 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +4
-0+ pcie0: pcie at 18012000 { + compatible = "brcm,iproc-pcie"; + reg = <0x18012000 0x1000>, + <0x18002000 0x1000>;I guess the addresses should be relative to the BCMA bus, and this node get moved under that. Please see Hauke's patch series, we've discussed this in great length already.
Quoted 8 lines
As Arend van Spriel pointed out in the previous discussion:
BCMA core is the bus driver for discoverable ARM AXI interconnect. Apart from that it also provides drivers for some cores. For the chips to be discoverable it needs additional IP logic.
Not all iProc family of SoCs have the additional IP logic and for those which don't, they cannot use the BCMA bus.
Ok, but the one from your example almost certainly does because the addresses are exactly the same ones as on bcm53xx.
The same problem likely occurs on other peripherals, not just PCI, so we will have to come up with a way to have a common driver for bcma_bus and platform_bus for USB, SPI, brcmsmac, and likely others too.
Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +9
-0+ #interrupt-cells = <1>; + interrupts = <GIC_SPI 96 IRQ_TYPE_NONE>, + <GIC_SPI 97 IRQ_TYPE_NONE>, + <GIC_SPI 98 IRQ_TYPE_NONE>, + <GIC_SPI 99 IRQ_TYPE_NONE>, + <GIC_SPI 100 IRQ_TYPE_NONE>, + <GIC_SPI 101 IRQ_TYPE_NONE>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>;
Quoted 8 lines
Quoted 4 lines
This interrupt is also listed in the "interrupts" above, which is probably a mistake, unless the IRQ line is shared between all PCI devices and the PCI host itself.
interrupts are for MSI interrupt support and interrupt-map is for legacy INTx support. To my best knowledge, MSI and INTx cannot be used at the same time. "nvidia,tegra20-pcie.txt" and "rcar-pci.txt" have similar configurations.
Linux drivers will absolutely use MSI and legacy interrupts together, because some drivers don't support MSI and others enable it unconditionally.
In both your examples (tegra and rcar), the interrupts that share the same number are auxiliary and are correctly used with IRQF_SHARED, so that works. If a device MSI just maps to a host IRQ however, you wouldn't be able to use IRQF_SHARED.
Arnd
Re: [PATCH v2 1/4] pci: iProc: define Broadcom iProc PCIe binding
Quoted 74 lines · Arnd Bergmann
Quoted 18 lines · On Friday 12 December 2014 08:53:44 Ray Jui wrote:
Quoted 16 lines · Arnd Bergmann
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 8
Quoted 12 lines · On Thursday 11 December 2014 18:36:54 Ray Jui wrote:
index 0000000..040bc0f
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +8
-0@@ -0,0 +1,74 @@ +* Broadcom iProc PCIe controller + +Required properties: +- compatible: Must be "brcm,iproc-pcie" +- reg: base address and length of the PCIe controller and the MDIO interface + that controls the PCIe PHY +- #interrupt-cells: set to<1> +- interrupts: interrupt IDsHow many, and what are they?
Quoted 2 lines
Different iProc SoCs might have different number of interrupts. I'll elaborate more on the next patch.
Ok.
Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +8
-0+- interrupt-map-mask and interrupt-map, standard PCI properties to define the + mapping of the PCIe interface to interrupt numbers +- bus-range: PCI bus numbers covered +- #address-cells: set to<3> +- #size-cells: set to<2> +- device_type: set to "pci" +- ranges: ranges for the PCI memory and I/O regions +- phy-addr: MDC/MDIO adddress of the PCIe PHYQuoted 7 lines
Quoted 4 lines
It looks like the phy controller is separate from the PCI controller, and you even list the same register range for both PHYs. Better make that a separate driver and put the phy address into the "phys" reference.
Okay. In this case, I need to create a separate PHY driver under the
drivers/phydirectory and have the PCIe host driver reference it through the standard PHY API.Yes, that is what I meant. In particular, that has the advantage of letting you reuse the two drivers separately if some new SoC comes up that uses one but not the other. A lot of PHY implementations can support multiple protocols (e.g. pcie and usb3), but I don't know if yours does.
Quoted 19 lines
Quoted 9 lines
Quoted 9 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +9
-0+- have-msi-inten-reg: Required for legacy iProc PCIe controllers that need the + MSI interrupt enable register to be set explicitly + +The Broadcom iProc PCie driver adapts the multi-domain structure, i.e., each +interface has its own domain and therefore has its own device node +Example: + +SoC specific DT Entry: +Quoted 9 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt line 29
Quoted 4 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +4
-0+ pcie0: pcie at 18012000 { + compatible = "brcm,iproc-pcie"; + reg =<0x18012000 0x1000>, +<0x18002000 0x1000>;I guess the addresses should be relative to the BCMA bus, and this node get moved under that. Please see Hauke's patch series, we've discussed this in great length already.
Quoted 8 lines
As Arend van Spriel pointed out in the previous discussion:
BCMA core is the bus driver for discoverable ARM AXI interconnect. Apart from that it also provides drivers for some cores. For the chips to be discoverable it needs additional IP logic.
Not all iProc family of SoCs have the additional IP logic and for those which don't, they cannot use the BCMA bus.
Quoted 7 lines
Ok, but the one from your example almost certainly does because the addresses are exactly the same ones as on bcm53xx.
The same problem likely occurs on other peripherals, not just PCI, so we will have to come up with a way to have a common driver for
bcma_busandplatform_busfor USB, SPI, brcmsmac, and likely others too.
Makes sense. I think that is what Hauke meant by "adding additional support for registering to bcma". So the discovery info is a piece of read-only memory in the chip. Its address is stored in the chipcommon core register space. BCMA parses that memory blob resulting in a list of cores which register address info. We could add DT support in BCMA matching the compatible string and register a core for it.
However, apart from the discovery info a "discoverable ARM AXI" chip has a register space per core that provides common procedures like enable/disable, reset, core status, which are implemented in BCMA. I am not seeing that register space in the DT examples so I guess this IP block is not there for iProc chips.
Regards,
Arend
Quoted 36 lines
Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
Documentation/devicetree/bindings/pci/brcm,iproc-pcie.txt new file +9
-0+ #interrupt-cells =<1>; + interrupts =<GIC_SPI 96 IRQ_TYPE_NONE>, +<GIC_SPI 97 IRQ_TYPE_NONE>, +<GIC_SPI 98 IRQ_TYPE_NONE>, +<GIC_SPI 99 IRQ_TYPE_NONE>, +<GIC_SPI 100 IRQ_TYPE_NONE>, +<GIC_SPI 101 IRQ_TYPE_NONE>; + interrupt-map-mask =<0 0 0 0>; + interrupt-map =<0 0 0 0&gic GIC_SPI 100 IRQ_TYPE_NONE>;Quoted 8 lines
Quoted 4 lines
This interrupt is also listed in the "interrupts" above, which is probably a mistake, unless the IRQ line is shared between all PCI devices and the PCI host itself.
interrupts are for MSI interrupt support and interrupt-map is for legacy INTx support. To my best knowledge, MSI and INTx cannot be used at the same time. "nvidia,tegra20-pcie.txt" and "rcar-pci.txt" have similar configurations.
Linux drivers will absolutely use MSI and legacy interrupts together, because some drivers don't support MSI and others enable it unconditionally.
In both your examples (tegra and rcar), the interrupts that share the same number are auxiliary and are correctly used with
IRQF_SHARED, so that works. If a device MSI just maps to a host IRQ however, you wouldn't be able to useIRQF_SHARED.Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v2 1/4] pci: iProc: define Broadcom iProc PCIe binding
Quoted 7 lines · On Saturday 13 December 2014 11:05:52 Arend van Spriel wrote:
Makes sense. I think that is what Hauke meant by "adding additional support for registering to bcma". So the discovery info is a piece of read-only memory in the chip. Its address is stored in the chipcommon core register space. BCMA parses that memory blob resulting in a list of cores which register address info. We could add DT support in BCMA matching the compatible string and register a core for it.
Ah, interesting idea. That would mirror what we do for drivers/amba, I like the idea.
Quoted 5 lines
However, apart from the discovery info a "discoverable ARM AXI" chip has a register space per core that provides common procedures like enable/disable, reset, core status, which are implemented in BCMA. I am not seeing that register space in the DT examples so I guess this IP block is not there for iProc chips.
I wouldn't draw conclusions from the absence of some node. Maybe these registers are present but just not used by the original BSP.
Arnd
Re: [PATCH v2 1/4] pci: iProc: define Broadcom iProc PCIe binding
Quoted 11 lines · Arnd Bergmann
Quoted 7 lines · On Saturday 13 December 2014 11:05:52 Arend van Spriel wrote:
Makes sense. I think that is what Hauke meant by "adding additional support for registering to bcma". So the discovery info is a piece of read-only memory in the chip. Its address is stored in the chipcommon core register space. BCMA parses that memory blob resulting in a list of cores which register address info. We could add DT support in BCMA matching the compatible string and register a core for it.
Ah, interesting idea. That would mirror what we do for
drivers/amba, I like the idea.
+ Rafal
Let's explore this. Although I don't have the iProc hardware to verify it.
Quoted 8 lines
Quoted 5 lines
However, apart from the discovery info a "discoverable ARM AXI" chip has a register space per core that provides common procedures like enable/disable, reset, core status, which are implemented in BCMA. I am not seeing that register space in the DT examples so I guess this IP block is not there for iProc chips.
I wouldn't draw conclusions from the absence of some node. Maybe these registers are present but just not used by the original BSP.
I do not intend to. We have raised the question internally to iProc chip designers.
Regards,
Arend
Re: [PATCH v2 1/4] pci: iProc: define Broadcom iProc PCIe binding
Quoted 10 lines · On Sunday 14 December 2014 10:48:01 Arend van Spriel wrote:
Quoted 9 lines · Arnd Bergmann
Quoted 7 lines · On Saturday 13 December 2014 11:05:52 Arend van Spriel wrote:
Makes sense. I think that is what Hauke meant by "adding additional support for registering to bcma". So the discovery info is a piece of read-only memory in the chip. Its address is stored in the chipcommon core register space. BCMA parses that memory blob resulting in a list of cores which register address info. We could add DT support in BCMA matching the compatible string and register a core for it.
Quoted 7 lines
Quoted 2 lines
Ah, interesting idea. That would mirror what we do for
drivers/amba, I like the idea.+ Rafal
Let's explore this. Although I don't have the iProc hardware to verify it.
If we can make this work nicely, you won't even need iProc hardware, but instead provide all the data for the bcma devices on an older machine through DT and get the probing to work with that. For AMBA, we actually allow mixing amba and platform devices on the same parent. You could do this here as well, but it would be simpler to have a a special bcma device node as the parent that does the probing, in order to avoid adding bcma specific code to drivers/of/platform.c
Arnd
Ray Jui
maintainerPATCH v2 2/4 PCI: iproc: Add Broadcom iProc PCIe driver
In reply to Ray JuiAdd initial version of the Broadcom iProc PCIe driver. This driver has been tested on NSP and Cygnus and is expected to work on all iProc family of SoCs that deploys the same PCIe host controller
The driver also supports MSI
--- drivers/pci/host/Kconfig | 9 + drivers/pci/host/Makefile | 1 + drivers/pci/host/pcie-iproc.c | 888 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 898 insertions(+) create mode 100644 drivers/pci/host/pcie-iproc.c
drivers/pci/host/Kconfig +9 -0
@@ -102,4 +102,13 @@ config PCI_LAYERSCAPE help Say Y here if you want PCIe controller support on Layerscape SoCs. +config PCIE_IPROC + bool "Broadcom iProc PCIe controller" + depends on ARCH_BCM_IPROC + help + Say Y here if you want to enable the PCIe controller driver support + on Broadcom's iProc family of SoCs. + + MSI is also supported in the driver. + endmenu
drivers/pci/host/Makefile +1 -0
@@ -12,3 +12,4 @@ obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o obj-$(CONFIG_PCI_XGENE) += pci-xgene.o obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o +obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o
drivers/pci/host/pcie-iproc.c new file +888 -0
888 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v2 2/4] PCI: iproc: Add Broadcom iProc PCIe driver
Quoted 5 lines · On Thursday 11 December 2014 18:36:55 Ray Jui wrote:
Add initial version of the Broadcom iProc PCIe driver. This driver has been tested on NSP and Cygnus and is expected to work on all iProc family of SoCs that deploys the same PCIe host controller
The driver also supports MSI
Overall, I'm not convinced it's worth continuing this driver. While it supports more features, Hauke's version seemed much cleaner, and I'd rather see his driver merged and have you add the additional features.
Why did you drop him from Cc again?
drivers/pci/host/pcie-iproc.c line 46
Quoted 7 lines
drivers/pci/host/pcie-iproc.c new file +7
-0+ +#define MII_MGMT_CTRL_OFFSET 0x000 +#define MII_MGMT_CTRL_MDCDIV_SHIFT 0 +#define MII_MGMT_CTRL_PRE_SHIFT 7 +#define MII_MGMT_CTRL_BUSY_SHIFT 8 +#define MII_MGMT_CTRL_EXT_SHIFT 9 +#define MII_MGMT_CTRL_BTP_SHIFT 10
As mentioned, better move all the MII handling to a separate driver.
Quoted 9 lines
drivers/pci/host/pcie-iproc.c new file +9
-0+struct iproc_pcie ; + +/** +* iProc MSI +* @pcie: pointer to the iProc PCIe data structure +* @irq_in_use: bitmap of MSI IRQs that are in use +* @domain: MSI IRQ domain +* @chip: MSI controller +* @eq_page: memory page to store the iProc MSI event queue
drivers/pci/host/pcie-iproc.c line 150
Quoted 10 lines
drivers/pci/host/pcie-iproc.c new file +10
-0+* @msi_page: memory page for MSI posted writes +*/ +struct iproc_msi { +struct iproc_pcie *pcie; + DECLARE_BITMAP(irq_in_use, MAX_IRQS); +struct irq_domain *domain; +struct msi_controller chip; +unsigned long eq_page; +unsigned long msi_page; +};
Same for MSI. I would assume that you will eventually have chips with this PCI core and a GICv2m or GICv3, so it would be better to reference the MSI controller through an msi-parent reference that can be replaced with a reference to the GIC.
Review
Quoted 2 lines
(quoted diff) +2
-0+ + u32 phy_addr;
struct phy *phy;
drivers/pci/host/pcie-iproc.c line 175
Quoted 1 line
drivers/pci/host/pcie-iproc.c new file +1
-0+int irqs[MAX_IRQS ];
Please name these irqs individually according to what they do. The MSI IRQ should of course be moved to the MSI driver.
Quoted 5 lines
drivers/pci/host/pcie-iproc.c new file +5
-0+struct iproc_msi msi; +}; + +static inline int mdio_wait_idle (struct iproc_pcie *pcie) +{
drivers/pci/host/pcie-iproc.c line 191
Quoted 10 lines
drivers/pci/host/pcie-iproc.c new file +10
-0+int timeout =MDIO_TIMEOUT_USEC ; + +while (readl (pcie->mii +MII_MGMT_CTRL_OFFSET ) & + (1 <<MII_MGMT_CTRL_BUSY_SHIFT )) { +udelay (1 ); +if (timeout-- <=0 ) +return -EBUSY ; + } +return 0 ; +}
Better use ktime_get()/ktime_add_ns()/ktime_before() loop here to do an accurate timeout.
drivers/pci/host/pcie-iproc.c line 289
Quoted 12 lines
drivers/pci/host/pcie-iproc.c new file +12
-0+static void iproc_pcie_reset (struct iproc_pcie *pcie) +{ +u32 val; + +/* send a downstream reset */ + val =EP_MODE_SURVIVE_PERST |RC_PCIE_RST_OUTPUT ; +writel (val, pcie->reg +CLK_CONTROL_OFFSET ); +udelay (250 ); + val &= ~EP_MODE_SURVIVE_PERST ; +writel (val, pcie->reg +CLK_CONTROL_OFFSET ); +mdelay (250 ); +}
250ms delay is not acceptable. Please find a way to call this function from a context in which you can sleep.
Quoted 18 lines
drivers/pci/host/pcie-iproc.c new file +18
-0+static int iproc_pcie_check_link (struct iproc_pcie *pcie) +{ +int ret; +u8 nlw; +u16 pos, tmp16; +u32 val; +struct pci_sys_data sys; +struct pci_bus bus; + + val =readl (pcie->reg +PCIE_LINK_STATUS_OFFSET ); +dev_dbg (pcie->dev,"link status: 0x%08x\n" , val); + + val =readl (pcie->reg +STRAP_STATUS_OFFSET ); +dev_dbg (pcie->dev,"strap status: 0x%08x\n" , val); + +memset (&sys,0 ,sizeof (sys)); +memset (&bus,0 ,sizeof (bus)); +
drivers/pci/host/pcie-iproc.c line 444
Quoted 10 lines
drivers/pci/host/pcie-iproc.c new file +10
-0+ bus.number =0 ; + bus.ops = &iproc_pcie_ops; + bus.sysdata = &sys; + sys.private_data = pcie; + + ret =iproc_pci_read_conf (&bus,0 ,PCI_HEADER_TYPE ,1 , &val); +if (ret !=PCIBIOS_SUCCESSFUL || val !=PCI_HEADER_TYPE_BRIDGE ) { +dev_err (pcie->dev,"in EP mode, val=0x08%x\n" , val); +return -EFAULT ; + }
Remove the fake pci_bus hack and just read the config space directly.
Quoted 7 lines
drivers/pci/host/pcie-iproc.c new file +7
-0+if (nlw ==0 ) { +/* try GEN 1 link speed */ +#define PCI_LINK_STATUS_CTRL_2_OFFSET 0xDC +#define PCI_TARGET_LINK_SPEED_MASK 0xF +#define PCI_TARGET_LINK_SPEED_GEN2 0x2 +#define PCI_TARGET_LINK_SPEED_GEN1 0x1 + pci_bus_read_config_dword(&bus, 0,
drivers/pci/host/pcie-iproc.c line 481
Quoted 10 lines
drivers/pci/host/pcie-iproc.c new file +10
-0+ PCI_LINK_STATUS_CTRL_2_OFFSET, &val); +if ((val &PCI_TARGET_LINK_SPEED_MASK ) == +PCI_TARGET_LINK_SPEED_GEN2 ) { + val &= ~PCI_TARGET_LINK_SPEED_MASK ; + val |=PCI_TARGET_LINK_SPEED_GEN1 ; +pci_bus_write_config_dword (&bus,0 , +PCI_LINK_STATUS_CTRL_2_OFFSET , val); +pci_bus_read_config_dword (&bus,0 , +PCI_LINK_STATUS_CTRL_2_OFFSET , &val); +mdelay (100 );
Too much delay.
Quoted 1 line
+static struct
hw_pcihw;
Put this on the stack.
Quoted 7 lines
drivers/pci/host/pcie-iproc.c new file +7
-0+ +/* Get the PCI memory ranges from DT */ +for_each_of_pci_range (&parser, &range) { +of_pci_range_to_resource (&range, np, &res); + +switch (res.flags &IORESOURCE_TYPE_BITS ) { +case IORESOURCE_IO :
drivers/pci/host/pcie-iproc.c line 838
Quoted 10 lines
drivers/pci/host/pcie-iproc.c new file +10
-0+memcpy (&pcie->io, &res,sizeof (res)); + pcie->io.name ="I/O" ; +break ; + +case IORESOURCE_MEM : +memcpy (&pcie->mem, &res,sizeof (res)); + pcie->mem.name ="MEM" ; +break ; + } + }
I think you need to request all the resources here, including the physical I/O space window.
drivers/pci/host/pcie-iproc.c line 877
Quoted 8 lines
drivers/pci/host/pcie-iproc.c new file +8
-0+static struct platform_driver iproc_pcie_driver = { + .driver = { + .owner =THIS_MODULE , + .name ="iproc-pcie" , + .of_match_table = +of_match_ptr (iproc_pcie_of_match_table), + }, +};
Make this a bcma_driver.
drivers/pci/host/pcie-iproc.c line 884
Quoted 6 lines
drivers/pci/host/pcie-iproc.c new file +6
-0+static int __init iproc_pcie_init (void ) +{ +return platform_driver_probe (&iproc_pcie_driver, + iproc_pcie_probe); +} +subsys_initcall (iproc_pcie_init);
module_init()? Doesn't seem necessary to have this early.
Arnd
Ray Jui
maintainerRe: [PATCH v2 2/4] PCI: iproc: Add Broadcom iProc PCIe driver
Quoted 5 lines · Arnd Bergmann
Quoted 4 lines · On Thursday 11 December 2014 18:36:55 Ray Jui wrote:
Add initial version of the Broadcom iProc PCIe driver. This driver has been tested on NSP and Cygnus and is expected to work on all iProc family of SoCs that deploys the same PCIe host controller
Quoted 8 lines
Quoted 1 line
The driver also supports MSI
Overall, I'm not convinced it's worth continuing this driver. While it supports more features, Hauke's version seemed much cleaner, and I'd rather see his driver merged and have you add the additional features.
Why did you drop him from Cc again?
In fact, Hauke is on the "to" list of all v2 patchset that I sent out. I added him to the "to" list because he mentioned during v1 patchset review that he'll help to test this on North Star.
Doesn't Hauke's driver depends on BCMA? In that case, how does it work on the SoCs that do not have the IP block to support BCMA?
Quoted 10 lines
drivers/pci/host/pcie-iproc.c line 46
Quoted 7 lines
drivers/pci/host/pcie-iproc.c new file +7
-0+ +#define MII_MGMT_CTRL_OFFSET 0x000 +#define MII_MGMT_CTRL_MDCDIV_SHIFT 0 +#define MII_MGMT_CTRL_PRE_SHIFT 7 +#define MII_MGMT_CTRL_BUSY_SHIFT 8 +#define MII_MGMT_CTRL_EXT_SHIFT 9 +#define MII_MGMT_CTRL_BTP_SHIFT 10As mentioned, better move all the MII handling to a separate driver.
Agreed.
Quoted 16 lines
Quoted 16 lines
drivers/pci/host/pcie-iproc.c new file +16
-0+struct iproc_pcie ; + +/** +* iProc MSI +* @pcie: pointer to the iProc PCIe data structure +* @irq_in_use: bitmap of MSI IRQs that are in use +* @domain: MSI IRQ domain +* @chip: MSI controller +* @eq_page: memory page to store the iProc MSI event queue +* @msi_page: memory page for MSI posted writes +*/ +struct iproc_msi { +struct iproc_pcie *pcie; + DECLARE_BITMAP(irq_in_use, MAX_IRQS); +struct irq_domain *domain; +struct msi_controller chip;
Quoted 9 lines
drivers/pci/host/pcie-iproc.c line 150
Quoted 3 lines
drivers/pci/host/pcie-iproc.c new file +3
-0+unsigned long eq_page; +unsigned long msi_page; +};Same for MSI. I would assume that you will eventually have chips with this PCI core and a GICv2m or GICv3, so it would be better to reference the MSI controller through an msi-parent reference that can be replaced with a reference to the GIC.
I'll need to look into this in more details.
Quoted 10 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ + u32 phy_addr;struct phy *phy;
drivers/pci/host/pcie-iproc.c line 175
Quoted 1 line
drivers/pci/host/pcie-iproc.c new file +1
-0+int irqs[MAX_IRQS ];Please name these irqs individually according to what they do. The MSI IRQ should of course be moved to the MSI driver.
Will investigate more on MSI.
Quoted 10 lines
Quoted 10 lines
drivers/pci/host/pcie-iproc.c new file +10
-0+struct iproc_msi msi; +}; + +static inline int mdio_wait_idle (struct iproc_pcie *pcie) +{ +int timeout =MDIO_TIMEOUT_USEC ; + +while (readl (pcie->mii +MII_MGMT_CTRL_OFFSET ) & + (1 <<MII_MGMT_CTRL_BUSY_SHIFT )) { +udelay (1 );
Quoted 9 lines
drivers/pci/host/pcie-iproc.c line 191
Quoted 5 lines
drivers/pci/host/pcie-iproc.c new file +5
-0+if (timeout-- <=0 ) +return -EBUSY ; + } +return 0 ; +}Better use ktime_get()/ktime_add_ns()/ktime_before() loop here to do an accurate timeout.
Sure. Will do that in the PHY driver.
Quoted 7 lines
Quoted 7 lines
drivers/pci/host/pcie-iproc.c new file +7
-0+static void iproc_pcie_reset (struct iproc_pcie *pcie) +{ +u32 val; + +/* send a downstream reset */ + val =EP_MODE_SURVIVE_PERST |RC_PCIE_RST_OUTPUT ; +writel (val, pcie->reg +CLK_CONTROL_OFFSET );
Quoted 9 lines
drivers/pci/host/pcie-iproc.c line 289
Quoted 5 lines
drivers/pci/host/pcie-iproc.c new file +5
-0+udelay (250 ); + val &= ~EP_MODE_SURVIVE_PERST ; +writel (val, pcie->reg +CLK_CONTROL_OFFSET ); +mdelay (250 ); +}250ms delay is not acceptable. Please find a way to call this function from a context in which you can sleep.
This is called from driver probe, where runs in the process context where you can sleep. Is my understanding correct? I can change mdelay to msleep so the CPU does not waste time spinning.
Quoted 22 lines
Quoted 22 lines
drivers/pci/host/pcie-iproc.c new file +22
-0+static int iproc_pcie_check_link (struct iproc_pcie *pcie) +{ +int ret; +u8 nlw; +u16 pos, tmp16; +u32 val; +struct pci_sys_data sys; +struct pci_bus bus; + + val =readl (pcie->reg +PCIE_LINK_STATUS_OFFSET ); +dev_dbg (pcie->dev,"link status: 0x%08x\n" , val); + + val =readl (pcie->reg +STRAP_STATUS_OFFSET ); +dev_dbg (pcie->dev,"strap status: 0x%08x\n" , val); + +memset (&sys,0 ,sizeof (sys)); +memset (&bus,0 ,sizeof (bus)); + + bus.number =0 ; + bus.ops = &iproc_pcie_ops; + bus.sysdata = &sys; + sys.private_data = pcie;
Quoted 9 lines
drivers/pci/host/pcie-iproc.c line 444
Quoted 6 lines
drivers/pci/host/pcie-iproc.c new file +6
-0+ + ret =iproc_pci_read_conf (&bus,0 ,PCI_HEADER_TYPE ,1 , &val); +if (ret !=PCIBIOS_SUCCESSFUL || val !=PCI_HEADER_TYPE_BRIDGE ) { +dev_err (pcie->dev,"in EP mode, val=0x08%x\n" , val); +return -EFAULT ; + }Remove the fake
pci_bushack and just read the config space directly.
Will look into this in more details.
Quoted 11 lines
Quoted 11 lines
drivers/pci/host/pcie-iproc.c new file +11
-0+if (nlw ==0 ) { +/* try GEN 1 link speed */ +#define PCI_LINK_STATUS_CTRL_2_OFFSET 0xDC +#define PCI_TARGET_LINK_SPEED_MASK 0xF +#define PCI_TARGET_LINK_SPEED_GEN2 0x2 +#define PCI_TARGET_LINK_SPEED_GEN1 0x1 +pci_bus_read_config_dword (&bus,0 , +PCI_LINK_STATUS_CTRL_2_OFFSET , &val); +if ((val &PCI_TARGET_LINK_SPEED_MASK ) == +PCI_TARGET_LINK_SPEED_GEN2 ) { + val &= ~PCI_TARGET_LINK_SPEED_MASK ;
Quoted 9 lines
drivers/pci/host/pcie-iproc.c line 481
Quoted 6 lines
drivers/pci/host/pcie-iproc.c new file +6
-0+ val |=PCI_TARGET_LINK_SPEED_GEN1 ; +pci_bus_write_config_dword (&bus,0 , +PCI_LINK_STATUS_CTRL_2_OFFSET , val); +pci_bus_read_config_dword (&bus,0 , +PCI_LINK_STATUS_CTRL_2_OFFSET , &val); +mdelay (100 );Too much delay.
Need to confirm with the ASIC engineer. The delay may be what's needed.
Quoted 16 lines
Quoted 1 line
+static struct
hw_pcihw;Put this on the stack.
Quoted 12 lines
drivers/pci/host/pcie-iproc.c new file +12
-0+ +/* Get the PCI memory ranges from DT */ +for_each_of_pci_range (&parser, &range) { +of_pci_range_to_resource (&range, np, &res); + +switch (res.flags &IORESOURCE_TYPE_BITS ) { +case IORESOURCE_IO : +memcpy (&pcie->io, &res,sizeof (res)); + pcie->io.name ="I/O" ; +break ; + +case IORESOURCE_MEM :
Quoted 9 lines
drivers/pci/host/pcie-iproc.c line 838
Quoted 5 lines
drivers/pci/host/pcie-iproc.c new file +5
-0+memcpy (&pcie->mem, &res,sizeof (res)); + pcie->mem.name ="MEM" ; +break ; + } + }I think you need to request all the resources here, including the physical I/O space window.
Okay.
Quoted 11 lines
drivers/pci/host/pcie-iproc.c line 877
Quoted 8 lines
drivers/pci/host/pcie-iproc.c new file +8
-0+static struct platform_driver iproc_pcie_driver = { + .driver = { + .owner =THIS_MODULE , + .name ="iproc-pcie" , + .of_match_table = +of_match_ptr (iproc_pcie_of_match_table), + }, +};Make this a
bcma_driver.
Cannot be a bcma driver. Reason explained above and in PATCH v2 1/4 emails.
Quoted 11 lines
drivers/pci/host/pcie-iproc.c line 884
Quoted 6 lines
drivers/pci/host/pcie-iproc.c new file +6
-0+static int __init iproc_pcie_init (void ) +{ +return platform_driver_probe (&iproc_pcie_driver, + iproc_pcie_probe); +} +subsys_initcall (iproc_pcie_init);
module_init()? Doesn't seem necessary to have this early.Arnd
Will look into this. Forgot why we use subsys_initcall here...
Re: [PATCH v2 2/4] PCI: iproc: Add Broadcom iProc PCIe driver
Quoted 13 lines · On Friday 12 December 2014 09:08:48 Ray Jui wrote:
Quoted 11 lines · Arnd Bergmann
Quoted 5 lines · On Thursday 11 December 2014 18:36:55 Ray Jui wrote:
Add initial version of the Broadcom iProc PCIe driver. This driver has been tested on NSP and Cygnus and is expected to work on all iProc family of SoCs that deploys the same PCIe host controller
The driver also supports MSI
Overall, I'm not convinced it's worth continuing this driver. While it supports more features, Hauke's version seemed much cleaner, and I'd rather see his driver merged and have you add the additional features.
Quoted 5 lines
Quoted 2 lines
Why did you drop him from Cc again?
In fact, Hauke is on the "to" list of all v2 patchset that I sent out. I added him to the "to" list because he mentioned during v1 patchset review that he'll help to test this on North Star.
Sorry, my mistake. I looked through the Cc list multiple times but failed to see him there.
Quoted 2 lines
Doesn't Hauke's driver depends on BCMA? In that case, how does it work on the SoCs that do not have the IP block to support BCMA?
I hadn't realized that there are some SoCs that are not BCMA based. As the host controller implementation is closely related, we will have to come up with some solution.
One way to solve this would be by turning the driver into a library the same way as the pcie-dw driver, and have separate front-ends for it for platform_device and bcma_device.
As I mentioned in my other reply, we will likely have the same problem in a number of other drivers too, so we could try to come up with a way to make bcma_device fit better into the platform_device infrastructure, but I wouldn't know how to do that without giving it more thought.
Quoted 16 lines
Quoted 7 lines
Quoted 7 lines
drivers/pci/host/pcie-iproc.c new file +7
-0+static void iproc_pcie_reset (struct iproc_pcie *pcie) +{ +u32 val; + +/* send a downstream reset */ + val =EP_MODE_SURVIVE_PERST |RC_PCIE_RST_OUTPUT ; +writel (val, pcie->reg +CLK_CONTROL_OFFSET );Quoted 9 lines
drivers/pci/host/pcie-iproc.c line 289
Quoted 5 lines
drivers/pci/host/pcie-iproc.c new file +5
-0+udelay (250 ); + val &= ~EP_MODE_SURVIVE_PERST ; +writel (val, pcie->reg +CLK_CONTROL_OFFSET ); +mdelay (250 ); +}250ms delay is not acceptable. Please find a way to call this function from a context in which you can sleep.
Quoted 3 lines
This is called from driver probe, where runs in the process context where you can sleep. Is my understanding correct? I can change mdelay to msleep so the CPU does not waste time spinning.
Right, that sounds good.
Quoted 20 lines
Quoted 11 lines
Quoted 11 lines
drivers/pci/host/pcie-iproc.c new file +11
-0+if (nlw ==0 ) { +/* try GEN 1 link speed */ +#define PCI_LINK_STATUS_CTRL_2_OFFSET 0xDC +#define PCI_TARGET_LINK_SPEED_MASK 0xF +#define PCI_TARGET_LINK_SPEED_GEN2 0x2 +#define PCI_TARGET_LINK_SPEED_GEN1 0x1 +pci_bus_read_config_dword (&bus,0 , +PCI_LINK_STATUS_CTRL_2_OFFSET , &val); +if ((val &PCI_TARGET_LINK_SPEED_MASK ) == +PCI_TARGET_LINK_SPEED_GEN2 ) { + val &= ~PCI_TARGET_LINK_SPEED_MASK ;Quoted 9 lines
drivers/pci/host/pcie-iproc.c line 481
Quoted 6 lines
drivers/pci/host/pcie-iproc.c new file +6
-0+ val |=PCI_TARGET_LINK_SPEED_GEN1 ; +pci_bus_write_config_dword (&bus,0 , +PCI_LINK_STATUS_CTRL_2_OFFSET , val); +pci_bus_read_config_dword (&bus,0 , +PCI_LINK_STATUS_CTRL_2_OFFSET , &val); +mdelay (100 );Too much delay.
Quoted 1 line
Need to confirm with the ASIC engineer. The delay may be what's needed.
If you can turn it into msleep here, it's fine. Just don't waste 100 million CPU cycles for no reason.
Quoted 9 lines
Quoted 9 lines
drivers/pci/host/pcie-iproc.c line 884
Quoted 6 lines
drivers/pci/host/pcie-iproc.c new file +6
-0+static int __init iproc_pcie_init (void ) +{ +return platform_driver_probe (&iproc_pcie_driver, + iproc_pcie_probe); +} +subsys_initcall (iproc_pcie_init);
module_init()? Doesn't seem necessary to have this early.
Quoted 3 lines
Quoted 2 lines
Arnd
Will look into this. Forgot why we use
subsys_initcallhere...
Probably copied from other drivers. It used to be required.
Arnd
Ray Jui
maintainerRe: [PATCH v2 2/4] PCI: iproc: Add Broadcom iProc PCIe driver
Quoted 10 lines · Arnd Bergmann
Quoted 4 lines · On Friday 12 December 2014 09:08:48 Ray Jui wrote:
On 12/12/2014 4:29 AM, Arnd Bergmann wrote:
Doesn't Hauke's driver depends on BCMA? In that case, how does it work on the SoCs that do not have the IP block to support BCMA?I hadn't realized that there are some SoCs that are not BCMA based. As the host controller implementation is closely related, we will have to come up with some solution.
I agree with you that we should have a common PCIe host driver which supports all iProc SoCs, BCM4708, BCM5301X, and some other similar SoCs.
Quoted 4 lines
One way to solve this would be by turning the driver into a library the same way as the pcie-dw driver, and have separate front-ends for it for
platform_deviceandbcma_device.
I'm fine with this solution, i.e., to introduce a common pcie-iproc core driver (just like pcie-designware) and have different front-ends depending on the device/bus type. If we end up deciding to go with this solution, I need to discuss with Hauke to come up with a plan to collaborate.
But before we choose to go with that route, may I ask, what is the purpose of tying a PCIe host driver to BCMA? What benefit does BCMA give us? If we have a generic platform based PCIe driver that can work on all iProc SoCs + BCM4708 and BCM5301X with all HW specific configurations taken care of by device tree, why do we still need to use BCMA?
I thought all a BCMA device here does is to auto-instantiate based on some register readings?
Re: [PATCH v2 2/4] PCI: iproc: Add Broadcom iProc PCIe driver
Quoted 11 lines · On Monday 15 December 2014 11:16:31 Ray Jui wrote:
Quoted 5 lines · Arnd Bergmann
On Friday 12 December 2014 09:08:48 Ray Jui wrote:
One way to solve this would be by turning the driver into a library the same way as the pcie-dw driver, and have separate front-ends for it forplatform_deviceandbcma_device.I'm fine with this solution, i.e., to introduce a common pcie-iproc core driver (just like pcie-designware) and have different front-ends depending on the device/bus type. If we end up deciding to go with this solution, I need to discuss with Hauke to come up with a plan to collaborate.
Ok
Quoted 8 lines
But before we choose to go with that route, may I ask, what is the purpose of tying a PCIe host driver to BCMA? What benefit does BCMA give us? If we have a generic platform based PCIe driver that can work on all iProc SoCs + BCM4708 and BCM5301X with all HW specific configurations taken care of by device tree, why do we still need to use BCMA?
I thought all a BCMA device here does is to auto-instantiate based on some register readings?
Basically, DT is a hack that we only need for nondiscoverable buses. As BCMA is (mostly) discoverable, we should use that, just like we do for things like PCI and USB. There are clearly some limitations to BCMA as well, e.g. on bcm4708 we don't have proper IRQ numbers in the device list and we need to work around that using DT, but overall it still seems to have more upsides than downsides to use it.
It's also good to point other SoC makers to Broadcom as a good example for how to do things they claim are impossible to do.
Arnd
Ray Jui
maintainerRe: [PATCH v2 2/4] PCI: iproc: Add Broadcom iProc PCIe driver
Quoted 31 lines · Arnd Bergmann
Quoted 11 lines · On Monday 15 December 2014 11:16:31 Ray Jui wrote:
Quoted 5 lines · Arnd Bergmann
On Friday 12 December 2014 09:08:48 Ray Jui wrote:
One way to solve this would be by turning the driver into a library the same way as the pcie-dw driver, and have separate front-ends for it forplatform_deviceandbcma_device.I'm fine with this solution, i.e., to introduce a common pcie-iproc core driver (just like pcie-designware) and have different front-ends depending on the device/bus type. If we end up deciding to go with this solution, I need to discuss with Hauke to come up with a plan to collaborate.
Ok
Quoted 8 lines
But before we choose to go with that route, may I ask, what is the purpose of tying a PCIe host driver to BCMA? What benefit does BCMA give us? If we have a generic platform based PCIe driver that can work on all iProc SoCs + BCM4708 and BCM5301X with all HW specific configurations taken care of by device tree, why do we still need to use BCMA?
I thought all a BCMA device here does is to auto-instantiate based on some register readings?
Basically, DT is a hack that we only need for nondiscoverable buses. As BCMA is (mostly) discoverable, we should use that, just like we do for things like PCI and USB. There are clearly some limitations to BCMA as well, e.g. on bcm4708 we don't have proper IRQ numbers in the device list and we need to work around that using DT, but overall it still seems to have more upsides than downsides to use it.
Quoted 5 lines
It's also good to point other SoC makers to Broadcom as a good example for how to do things they claim are impossible to do.
Arnd
Okay. Fair enough. Let's go with your proposal to create a generic driver pcie-iproc to be used by both bcma and platform bus. I'll initiate another email thread with you, Hauke, Scott, and me. We can discuss how to collaborate on that email thread.
Thanks.
Ray Jui
maintainerPATCH v2 3/4 ARM: mach-bcm: Enable PCIe support for iProc
In reply to Ray JuiEnable PCIe driver support for Broadcom iProc family of SoCs by selecting PCIE_IPROC
--- arch/arm/mach-bcm/Kconfig | 1 + 1 file changed, 1 insertion(+)
arch/arm/mach-bcm/Kconfig +1 -0
@@ -19,6 +19,7 @@ config ARCH_BCM_IPROC select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select PINCTRL + select PCIE_IPROC help This enables support for systems based on Broadcom IPROC architected SoCs. The IPROC complex contains one or more ARM CPUs along with common
Signature · 1 line
1.7.9.5
Re: [PATCH v2 3/4] ARM: mach-bcm: Enable PCIe support for iProc
Quoted 15 lines · On Thursday 11 December 2014 18:36:56 Ray Jui wrote:
Enable PCIe driver support for Broadcom iProc family of SoCs by selecting
PCIE_IPROCSigned-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- arch/arm/mach-bcm/Kconfig | 1 + 1 file changed, 1 insertion(+)arch/arm/mach-bcm/Kconfig +0
-0
arch/arm/mach-bcm/Kconfig config ARCH_BCM_IPROC · line 25
Quoted 7 lines
arch/arm/mach-bcm/Kconfig +1
-0@@ -19,6 +19,7 @@ config ARCH_BCM_IPROC select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select PINCTRL + select PCIE_IPROC help This enables support for systems based on Broadcom IPROC architected SoCs. The IPROC complex contains one or more ARM CPUs along with common
No, just enable it in multi_v7_defconfig and bcm_defconfig.
Arnd
Ray Jui
maintainerRe: [PATCH v2 3/4] ARM: mach-bcm: Enable PCIe support for iProc
Quoted 26 lines · Arnd Bergmann
Quoted 15 lines · On Thursday 11 December 2014 18:36:56 Ray Jui wrote:
Enable PCIe driver support for Broadcom iProc family of SoCs by selecting
PCIE_IPROCSigned-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- arch/arm/mach-bcm/Kconfig | 1 + 1 file changed, 1 insertion(+)arch/arm/mach-bcm/Kconfig +0
-0arch/arm/mach-bcm/Kconfig config ARCH_BCM_IPROC · line 25
Quoted 7 lines
arch/arm/mach-bcm/Kconfig +1
-0@@ -19,6 +19,7 @@ config ARCH_BCM_IPROC select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select PINCTRL + select PCIE_IPROC help This enables support for systems based on Broadcom IPROC architected SoCs. The IPROC complex contains one or more ARM CPUs along with commonNo, just enable it in
multi_v7_defconfigandbcm_defconfig.
Quoted 2 lines
Arnd
Or can I simply have the PCIE_IPROC default to y in drivers/pci/host/Kconfig? Note PCIE_IPROC depends on ARCH_BCM_IPROC. By defaulting it to y, it will be automatically enabled for all iProc family of SoCs.
Re: [PATCH v2 3/4] ARM: mach-bcm: Enable PCIe support for iProc
Quoted 17 lines · On Friday 12 December 2014 08:56:19 Ray Jui wrote:
Quoted 17 lines
Quoted 7 lines
arch/arm/mach-bcm/Kconfig +0
-0arch/arm/mach-bcm/Kconfig config ARCH_BCM_IPROC · line 25
Quoted 7 lines
arch/arm/mach-bcm/Kconfig +1
-0@@ -19,6 +19,7 @@ config ARCH_BCM_IPROC select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select PINCTRL + select PCIE_IPROC help This enables support for systems based on Broadcom IPROC architected SoCs. The IPROC complex contains one or more ARM CPUs along with commonNo, just enable it in
multi_v7_defconfigandbcm_defconfig.
Quoted 6 lines
Quoted 2 lines
Arnd
Or can I simply have the
PCIE_IPROCdefault to y indrivers/pci/host/Kconfig? NotePCIE_IPROCdepends onARCH_BCM_IPROC. By defaulting it to y, it will be automatically enabled for all iProc family of SoCs.
I still think it's best not to turn it on automatically. The convention for device drivers is to make them all optional.
What you can do however is to add
depends on ARCH_BCM_IPROC || COMPILE_TEST
to the driver to do the reverse and not let the driver be turned on unless IPROC is selected or you are just testing the build. A lot of distros just turn on all drivers, so this way you wouldn't accidentally enable it for a kernel that doesn't support IPROC.
Arnd
Ray Jui
maintainerRe: [PATCH v2 3/4] ARM: mach-bcm: Enable PCIe support for iProc
Quoted 30 lines · Arnd Bergmann
Quoted 17 lines · On Friday 12 December 2014 08:56:19 Ray Jui wrote:
Quoted 17 lines
Quoted 7 lines
arch/arm/mach-bcm/Kconfig +0
-0arch/arm/mach-bcm/Kconfig config ARCH_BCM_IPROC · line 25
Quoted 7 lines
arch/arm/mach-bcm/Kconfig +1
-0@@ -19,6 +19,7 @@ config ARCH_BCM_IPROC select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select PINCTRL + select PCIE_IPROC help This enables support for systems based on Broadcom IPROC architected SoCs. The IPROC complex contains one or more ARM CPUs along with commonNo, just enable it in
multi_v7_defconfigandbcm_defconfig.Quoted 6 lines
Quoted 2 lines
Arnd
Or can I simply have the
PCIE_IPROCdefault to y indrivers/pci/host/Kconfig? NotePCIE_IPROCdepends onARCH_BCM_IPROC. By defaulting it to y, it will be automatically enabled for all iProc family of SoCs.I still think it's best not to turn it on automatically. The convention for device drivers is to make them all optional.
What you can do however is to add
Quoted 9 lines
depends on ARCH_BCM_IPROC || COMPILE_TESTto the driver to do the reverse and not let the driver be turned on unless IPROC is selected or you are just testing the build. A lot of distros just turn on all drivers, so this way you wouldn't accidentally enable it for a kernel that doesn't support IPROC.
Arnd
Okay I'll do that. Thanks.
Ray Jui
maintainerPATCH v2 4/4 ARM: dts: enable PCIe for Broadcom Cygnus
In reply to Ray JuiAdd PCIe device nodes and its properties in bcm-cygnus.dtsi but keep it disabled there. Only enable it in bcm958300k.dts because PCIe interfaces are only populated on that board
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 52 +++++++++++++++++++++++++++++++++++++ arch/arm/boot/dts/bcm958300k.dts | 8 ++++++ 2 files changed, 60 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +52 -0
@@ -70,6 +70,58 @@ }; }; + pcie0: pcie@18012000 { + compatible = "brcm,iproc-pcie"; + reg = <0x18012000 0x1000>, + <0x18002000 0x1000>; + + #interrupt-cells = <1>; + interrupts = <GIC_SPI 96 IRQ_TYPE_NONE>, + <GIC_SPI 97 IRQ_TYPE_NONE>, + <GIC_SPI 98 IRQ_TYPE_NONE>, + <GIC_SPI 99 IRQ_TYPE_NONE>, + <GIC_SPI 100 IRQ_TYPE_NONE>, + <GIC_SPI 101 IRQ_TYPE_NONE>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>; + + bus-range = <0x00 0xFF>; + + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x28000000 0 0x00010000 + 0x82000000 0 0x20000000 0x20000000 0 0x04000000>; + phy-addr = <5>; + status = "disabled"; + }; + + pcie1: pcie@18013000 { + compatible = "brcm,iproc-pcie"; + reg = <0x18013000 0x1000>, + <0x18002000 0x1000>; + + #interrupt-cells = <1>; + interrupts = <GIC_SPI 102 IRQ_TYPE_NONE>, + <GIC_SPI 103 IRQ_TYPE_NONE>, + <GIC_SPI 104 IRQ_TYPE_NONE>, + <GIC_SPI 105 IRQ_TYPE_NONE>, + <GIC_SPI 106 IRQ_TYPE_NONE>, + <GIC_SPI 107 IRQ_TYPE_NONE>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 106 IRQ_TYPE_NONE>; + + bus-range = <0x00 0xFF>; + + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x48000000 0 0x00010000 + 0x82000000 0 0x40000000 0x40000000 0 0x04000000>; + phy-addr = <6>; + status = "disabled"; + }; + uart0: serial@18020000 { compatible = "snps,dw-apb-uart"; reg = <0x18020000 0x100>;
arch/arm/boot/dts/bcm958300k.dts +8 -0
@@ -47,6 +47,14 @@ bootargs = "console=ttyS0,115200"; }; + pcie0: pcie@18012000 { + status = "okay"; + }; + + pcie1: pcie@18013000 { + status = "okay"; + }; + uart3: serial@18023000 { status = "okay"; };
Signature · 1 line
1.7.9.5
Ray Jui
maintainerv6 cover Add gpio support to Broadcom Cygnus SoC
In reply to a message not in the archiveThis patchset contains the initial GPIO support for the Broadcom Cygnus SoC. Cygnus has 3 GPIO controllers: 1) the ASIU GPIO; 2) the chipCommonG GPIO; and 3) the ALWAYS-ON GPIO. All 3 types of GPIO controllers are supported by the same Cygnus GPIO driver
Changes from v5:
- Get rid of DT property "linux,gpio-base". Use dynamic allocation for GPIO base number
Changes from v4:
- Use DT property "linux,gpio-base" to define GPIO base number
- factorize common code to improve code readability and reduce code size
- remove "bcm_" prefix on function and struct names
- improve debugging prints
- default GPIO_BCM_CYGNUS to y in Kconfig (it still depends on ARCH_BCM_CYGNUS). This way we do not need to select it from the arch/arm/mach-bcm/Kconfig
- Get rid of redundant MAINTAINER entry for this driver. It will be maintained by Broadcom iProc/Cygnus maintainers
- Update device tree document based on driver changes
Changes from v3:
- Fix dt property tpyo
- Fix incorrect GPIO compatible ID in device tree binding document example
Changes from v2:
- Consolidate different compatible IDs into "brcm,cygnus-gpio"
- Get rid of redundant "no-interrupt" property
Changes from v1:
- Get rid of inline qualifier
- Get rid of redundant check in the ISR
- Other minor fixes to imrove code readability
Ray Jui (3):
gpio: Cygnus: define Broadcom Cygnus GPIO binding
gpio: Cygnus: add GPIO driver
ARM: dts: enable GPIO for Broadcom Cygnus
.../devicetree/bindings/gpio/brcm,cygnus-gpio.txt | 82 +++ arch/arm/boot/dts/bcm-cygnus.dtsi | 30 + drivers/gpio/Kconfig | 12 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-bcm-cygnus.c | 607 ++++++++++++++++++++ 5 files changed, 732 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt create mode 100644 drivers/gpio/gpio-bcm-cygnus.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v6 1/3 gpio: Cygnus: define Broadcom Cygnus GPIO binding
Document the GPIO device tree binding for Broadcom Cygnus SoC
--- .../devicetree/bindings/gpio/brcm,cygnus-gpio.txt | 82 ++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt
Documentation/devicetree/bindings/gpio/brcm,cygnus-gpio.txt new file +82 -0
@@ -0,0 +1,82 @@ +Broadcom Cygnus GPIO Controller + +Required properties: + +- compatible: + Must be "brcm,cygnus-gpio" + +- reg: + Define the base and range of the I/O address space that contain the Cygnus +GPIO controller registers + +- ngpios: + Total number of GPIOs the controller provides + +- #gpio-cells: + Must be two. The first cell is the GPIO pin number (within the +controller's domain) and the second cell is used for the following: + bit[0]: polarity (0 for normal and 1 for inverted) + bit[18:16]: internal pull up/down: 0 - pull up/down disabled + 1 - pull up enabled + 2 - pull down enabled + bit[22:20]: drive strength: 0 - 2 mA + 1 - 4 mA + 2 - 6 mA + 3 - 8 mA + 4 - 10 mA + 5 - 12 mA + 6 - 14 mA + 7 - 16 mA + +- gpio-controller: + Specifies that the node is a GPIO controller + +Optional properties: + +- interrupt-controller: + Specifies that the node is an interrupt controller. Not all Cygnus GPIO +interfaces support interrupt, e.g., the CRMU GPIO controller does not have its +interrupt routed to the main processor's GIC + +- interrupts: + The interrupt outputs from the GPIO controller. + +- no-drv-strength: + Specifies the GPIO controller does not support drive strength configuration + +Example: + gpio_asiu: gpio at 180a5000 { + compatible = "brcm,cygnus-gpio"; + reg = <0x180a5000 0x668>; + ngpios = <122>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; + }; + + gpio_crmu: gpio at 03024800 { + compatible = "brcm,cygnus-gpio"; + reg = <0x03024800 0x50>; + ngpios = <6>; + #gpio-cells = <2>; + gpio-controller; + no-drv-strength; + }; + + /* + * Touchscreen that uses the ASIU GPIO 100, with internal pull-up + * enabled + */ + tsc { + ... + ... + gpio-event = <&gpio_asiu 100 0x10000>; + }; + + /* Bluetooth that uses the CRMU GPIO 2, with polarity inverted */ + bluetooth { + ... + ... + bcm,rfkill-bank-sel = <&gpio_crmu 2 1> + }
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v6 2/3 gpio: Cygnus: add GPIO driver
In reply to Ray JuiThis GPIO driver supports all 3 GPIO controllers in the Broadcom Cygnus SoC. The 3 GPIO controllers are 1) the ASIU GPIO controller, 2) the chipCommonG GPIO controller, and 3) the ALWAYS-ON GPIO controller
--- drivers/gpio/Kconfig | 12 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-bcm-cygnus.c | 607 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 620 insertions(+) create mode 100644 drivers/gpio/gpio-bcm-cygnus.c
drivers/gpio/Kconfig +12 -0
@@ -126,6 +126,18 @@ config GPIO_74XX_MMIO 8 bits: 74244 (Input), 74273 (Output) 16 bits: 741624 (Input), 7416374 (Output) +config GPIO_BCM_CYGNUS + bool "Broadcom Cygnus GPIO support" + depends on ARCH_BCM_CYGNUS && OF_GPIO + default y + help + Say yes here to turn on GPIO support for Broadcom Cygnus SoC + + The Broadcom Cygnus SoC has 3 GPIO controllers including the ASIU + GPIO controller (ASIU), the chipCommonG GPIO controller (CCM), and + the always-ON GPIO controller (CRMU). All 3 GPIO controllers are + supported by this driver + config GPIO_CLPS711X tristate "CLPS711X GPIO support" depends on ARCH_CLPS711X || COMPILE_TEST
drivers/gpio/Makefile +1 -0
@@ -19,6 +19,7 @@ obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o +obj-$(CONFIG_GPIO_BCM_CYGNUS) += gpio-bcm-cygnus.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
drivers/gpio/gpio-bcm-cygnus.c new file +607 -0
607 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v6 2/3] gpio: Cygnus: add GPIO driver
Quoted 6 lines · Ray Jui
This GPIO driver supports all 3 GPIO controllers in the Broadcom Cygnus SoC. The 3 GPIO controllers are 1) the ASIU GPIO controller, 2) the chipCommonG GPIO controller, and 3) the ALWAYS-ON GPIO controller
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>
(Big thanks to Alexandre for doing the major part of the review, good work with following up so far!)
(...)
drivers/gpio/Kconfig config GPIO_74XX_MMIO · line 131
Quoted 3 lines
drivers/gpio/Kconfig +3
-0+config GPIO_BCM_CYGNUS + bool "Broadcom Cygnus GPIO support" + depends on ARCH_BCM_CYGNUS && OF_GPIO
select GPIOLIB_IRQCHIP
See more about this below.
Quoted 16 lines
+++
b/drivers/gpio/gpio-bcm-cygnus.cdrivers/gpio/gpio-bcm-cygnus.c new file +14
-0@@ -0,0 +1,607 @@ +/* +* Copyright (C) 2014 Broadcom Corporation +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/kernel.h>
drivers/gpio/gpio-bcm-cygnus.c line 24
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+#include <linux/slab.h> +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/ioport.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/irqchip/chained_irq.h>
Skip <linux/irq.h> and <linux/irqchip/chained_irq.h> as these move to the core with GPIOLIB_IRQCHIP
Quoted 8 lines
drivers/gpio/gpio-bcm-cygnus.c new file +8
-0+#define CYGNUS_GPIO_DATA_IN_OFFSET 0x00 +#define CYGNUS_GPIO_DATA_OUT_OFFSET 0x04 +#define CYGNUS_GPIO_OUT_EN_OFFSET 0x08 +#define CYGNUS_GPIO_IN_TYPE_OFFSET 0x0c +#define CYGNUS_GPIO_INT_DE_OFFSET 0x10 +#define CYGNUS_GPIO_INT_EDGE_OFFSET 0x14 +#define CYGNUS_GPIO_INT_MSK_OFFSET 0x18 +#define CYGNUS_GPIO_INT_STAT_OFFSET 0x1c
drivers/gpio/gpio-bcm-cygnus.c line 43
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+#define CYGNUS_GPIO_INT_MSTAT_OFFSET 0x20 +#define CYGNUS_GPIO_INT_CLR_OFFSET 0x24 +#define CYGNUS_GPIO_PAD_RES_OFFSET 0x34 +#define CYGNUS_GPIO_RES_EN_OFFSET 0x38 + +/* drive strength control for ASIU GPIO */ +#define CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58 + +/* drive strength control for CCM GPIO */ +#define CYGNUS_GPIO_CCM_DRV0_CTRL_OFFSET 0x00
This stuff (drive strength) is pin control, pin config. It does not belong in a pure GPIO driver. If you're making a combined pin control + GPIO driver, it shall be put in drivers/pinctrl/*
Quoted 29 lines
drivers/gpio/gpio-bcm-cygnus.c new file +29
-0+#define GPIO_BANK_SIZE 0x200 +#define NGPIOS_PER_BANK 32 +#define GPIO_BANK (pin) ((pin) / NGPIOS_PER_BANK) + +#define CYGNUS_GPIO_REG (pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg)) +#define CYGNUS_GPIO_SHIFT (pin) ((pin) % NGPIOS_PER_BANK) + +#define GPIO_FLAG_BIT_MASK 0xffff +#define GPIO_PULL_BIT_SHIFT 16 +#define GPIO_PULL_BIT_MASK 0x3 + +#define GPIO_DRV_STRENGTH_BIT_SHIFT 20 +#define GPIO_DRV_STRENGTH_BITS 3 +#define GPIO_DRV_STRENGTH_BIT_MASK ((1 << GPIO_DRV_STRENGTH_BITS) - 1) + +/* +* For GPIO internal pull up/down registers +*/ +enum gpio_pull { +GPIO_PULL_NONE =0 , +GPIO_PULL_UP , +GPIO_PULL_DOWN , +GPIO_PULL_INVALID , +}; + +/* +* GPIO drive strength +*/ +enum gpio_drv_strength {
drivers/gpio/gpio-bcm-cygnus.c line 83
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+GPIO_DRV_STRENGTH_2MA =0 , +GPIO_DRV_STRENGTH_4MA , +GPIO_DRV_STRENGTH_6MA , +GPIO_DRV_STRENGTH_8MA , +GPIO_DRV_STRENGTH_10MA , +GPIO_DRV_STRENGTH_12MA , +GPIO_DRV_STRENGTH_14MA , +GPIO_DRV_STRENGTH_16MA , + GPIO_DRV_STRENGTH_INVALID, +};
All this pull up/down and drive strength is pin config for the pin control subsystem.
drivers/gpio/gpio-bcm-cygnus.c line 93
Quoted 9 lines
drivers/gpio/gpio-bcm-cygnus.c new file +9
-0+struct cygnus_gpio { +struct device *dev; +void __iomem *base; +void __iomem *io_ctrl; +spinlock_t lock; +struct gpio_chip gc; +unsigned num_banks; +int irq; +struct irq_domain *irq_domain;
Skip irq and irqdomain and use GPIOLIB_IRQCHIP
drivers/gpio/gpio-bcm-cygnus.c line 110
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+static u32 cygnus_readl (struct cygnus_gpio *cygnus_gpio,unsigned int offset) +{ +return readl (cygnus_gpio->base + offset); +} + +static void cygnus_writel (struct cygnus_gpio *cygnus_gpio, +unsigned int offset,u32 val) +{ +writel (val, cygnus_gpio->base + offset); +}
I don't see the value of using these accessors over just inlining your readl/writel stuff.
(...)
drivers/gpio/gpio-bcm-cygnus.c line 141
Quoted 6 lines
drivers/gpio/gpio-bcm-cygnus.c new file +6
-0+static int cygnus_gpio_to_irq (struct gpio_chip *gc,unsigned offset) +{ +struct cygnus_gpio *cygnus_gpio =to_cygnus_gpio (gc); + +return irq_find_mapping (cygnus_gpio->irq_domain, offset); +}
This goes away to the core with GPIOLIB_IRQCHIP
Quoted 24 lines
drivers/gpio/gpio-bcm-cygnus.c new file +24
-0+static void cygnus_gpio_irq_handler (unsigned int irq,struct irq_desc *desc) +{ +struct cygnus_gpio *cygnus_gpio; +struct irq_chip *chip =irq_desc_get_chip (desc); +int i, bit; + +chained_irq_enter (chip, desc); + + cygnus_gpio =irq_get_handler_data (irq); + +/* go through the entire GPIO banks and handle all interrupts */ +for (i =0 ; i < cygnus_gpio->num_banks; i++) { +unsigned long val =cygnus_readl (cygnus_gpio, + (i *GPIO_BANK_SIZE ) + +CYGNUS_GPIO_INT_MSTAT_OFFSET ); + +for_each_set_bit (bit, &val,NGPIOS_PER_BANK ) { +unsigned pin =NGPIOS_PER_BANK * i + bit; +int child_irq = +cygnus_gpio_to_irq (&cygnus_gpio->gc, pin); + +/* +* Clear the interrupt before invoking the +* handler, so we do not leave any window
drivers/gpio/gpio-bcm-cygnus.c line 176
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+*/ +cygnus_writel (cygnus_gpio, (i *GPIO_BANK_SIZE ) + +CYGNUS_GPIO_INT_CLR_OFFSET ,BIT (bit)); + +generic_handle_irq (child_irq); + } + } + +chained_irq_exit (chip, desc); +}
Looks good, but you will need to have the struct gpio_chip * as handler data to use GPIOLIB_IRQCHIP, so get from there to the struct cygnus_gpio something like:
struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct cygnus_gpio *cyg = to_cygnus_gpio(gc);
drivers/gpio/gpio-bcm-cygnus.c line 336
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+static int cygnus_gpio_get (struct gpio_chip *gc,unsigned gpio) +{ +struct cygnus_gpio *cygnus_gpio =to_cygnus_gpio (gc); +unsigned int offset =CYGNUS_GPIO_REG (gpio, +CYGNUS_GPIO_DATA_IN_OFFSET ); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); +u32 val; + + val =cygnus_readl (cygnus_gpio, offset); + val = (val >> shift) &1 ;
No, do this:
return !!(cygnus_readl(cygnus_gpio, offset) & BIT(shift));
Maybe rename the "shift" variable to "bit" or just use the macro directly in the readl().
Quoted 17 lines
drivers/gpio/gpio-bcm-cygnus.c new file +17
-0+static int cygnus_gpio_irq_map (struct irq_domain *d,unsigned int irq, +irq_hw_number_t hwirq) +{ +int ret; + + ret =irq_set_chip_data (irq, d->host_data); +if (ret <0 ) +return ret; +irq_set_lockdep_class (irq, &gpio_lock_class); +irq_set_chip_and_handler (irq, &cygnus_gpio_irq_chip, + handle_simple_irq); +set_irq_flags (irq,IRQF_VALID ); + +return 0 ; +} + +static void cygnus_gpio_irq_unmap (struct irq_domain *d,unsigned int irq)
drivers/gpio/gpio-bcm-cygnus.c line 371
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+{ +irq_set_chip_and_handler (irq,NULL ,NULL ); +irq_set_chip_data (irq,NULL ); +} + +static struct irq_domain_ops cygnus_irq_ops = { + .map = cygnus_gpio_irq_map, + .unmap = cygnus_gpio_irq_unmap, + .xlate = irq_domain_xlate_twocell, +};
All this goes away with GPIOLIB_IRQCHIP (that is what is good about it).
Review line 178
Quoted 1 line
(quoted diff) +1
-0+#ifdef CONFIG_OF_GPIO
What, that should be defined all the time, you depend on it in Kconfig!
Quoted 2 lines
drivers/gpio/gpio-bcm-cygnus.c new file +2
-0+static void cygnus_gpio_set_pull (struct cygnus_gpio *cygnus_gpio, +unsigned gpio,enum gpio_pull pull)
(...)
Quoted 2 lines
drivers/gpio/gpio-bcm-cygnus.c new file +2
-0+static void cygnus_gpio_set_strength (struct cygnus_gpio *cygnus_gpio, +unsigned gpio,enum gpio_drv_strength strength)
(...)
drivers/gpio/gpio-bcm-cygnus.c line 448
Quoted 2 lines
drivers/gpio/gpio-bcm-cygnus.c new file +2
-0+static int cygnus_gpio_of_xlate (struct gpio_chip *gc, +const struct of_phandle_args *gpiospec,u32 *flags)
NAK. This is pin control, put this in the pin control driver.
I guess the same that is part of this patch series.
(...)
Quoted 32 lines
drivers/gpio/gpio-bcm-cygnus.c new file +32
-0+static int cygnus_gpio_probe (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +struct resource *res; +struct cygnus_gpio *cygnus_gpio; +struct gpio_chip *gc; +u32 i, ngpios; +int ret; + + cygnus_gpio =devm_kzalloc (dev,sizeof (*cygnus_gpio),GFP_KERNEL ); +if (!cygnus_gpio) +return -ENOMEM ; + + cygnus_gpio->dev = dev; +platform_set_drvdata (pdev, cygnus_gpio); + +if (of_property_read_u32 (dev->of_node,"ngpios" , &ngpios)) { +dev_err (&pdev->dev,"missing ngpios DT property\n" ); +return -ENODEV ; + } + cygnus_gpio->num_banks = (ngpios +NGPIOS_PER_BANK -1 ) / +NGPIOS_PER_BANK ; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + cygnus_gpio->base =devm_ioremap_resource (dev, res); +if (IS_ERR (cygnus_gpio->base)) { +dev_err (&pdev->dev,"unable to map I/O memory\n" ); +return PTR_ERR (cygnus_gpio->base); + } + +/* +* Only certain types of Cygnus GPIO interfaces have I/O control
drivers/gpio/gpio-bcm-cygnus.c line 527
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+* registers +*/ + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (res) { + cygnus_gpio->io_ctrl =devm_ioremap_resource (dev, res); +if (IS_ERR (cygnus_gpio->io_ctrl)) { +dev_err (&pdev->dev,"unable to map I/O memory\n" ); +return PTR_ERR (cygnus_gpio->io_ctrl); + } + }
This is a good indication that it's a separate piece of HW and should be a separate pin control driver.
drivers/gpio/gpio-bcm-cygnus.c line 536
Quoted 9 lines
drivers/gpio/gpio-bcm-cygnus.c new file +9
-0+ +spin_lock_init (&cygnus_gpio->lock); + + gc = &cygnus_gpio->gc; + gc->base =-1 ; + gc->ngpio = ngpios; + gc->label =dev_name (dev); + gc->dev = dev; +#ifdef CONFIG_OF_GPIO
You depend on this symbol.
Quoted 41 lines
drivers/gpio/gpio-bcm-cygnus.c new file +28
-0+ gc->of_node = dev->of_node; + gc->of_gpio_n_cells =2 ; + gc->of_xlate = cygnus_gpio_of_xlate; +#endif + gc->direction_input = cygnus_gpio_direction_input; + gc->direction_output = cygnus_gpio_direction_output; + gc->set = cygnus_gpio_set; + gc->get = cygnus_gpio_get; + gc->to_irq = cygnus_gpio_to_irq; + + ret =gpiochip_add (gc); +if (ret <0 ) { +dev_err (&pdev->dev,"unable to add GPIO chip\n" ); +return ret; + } + +/* +* Some of the GPIO interfaces do not have interrupt wired to the main +* processor +*/ + cygnus_gpio->irq =platform_get_irq (pdev,0 ); +if (cygnus_gpio->irq <0 ) { + ret = cygnus_gpio->irq; +if (ret == -EPROBE_DEFER ) + goto err_rm_gpiochip; + +dev_info (&pdev->dev,"no interrupt hook\n" ); + }From here:
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+ cygnus_gpio->irq_domain =irq_domain_add_linear (dev->of_node, + gc->ngpio, &cygnus_irq_ops, cygnus_gpio); +if (!cygnus_gpio->irq_domain) { +dev_err (&pdev->dev,"unable to allocate IRQ domain\n" ); + ret = -ENXIO ; + goto err_rm_gpiochip; + } + +for (i =0 ; i < gc->ngpio; i++) { +int irq =irq_create_mapping (cygnus_gpio->irq_domain, i);
drivers/gpio/gpio-bcm-cygnus.c line 585
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+ +irq_set_lockdep_class (irq, &gpio_lock_class); +irq_set_chip_data (irq, cygnus_gpio); +irq_set_chip_and_handler (irq, &cygnus_gpio_irq_chip, + handle_simple_irq); +set_irq_flags (irq,IRQF_VALID ); + } + +irq_set_chained_handler (cygnus_gpio->irq, cygnus_gpio_irq_handler); +irq_set_handler_data (cygnus_gpio->irq, cygnus_gpio);
To here, replace with a single call to gpiochip_set_chained_irqchip(chip *, irq_chip *, irq, handler)...
Look at other drivers using GPIOLIB_IRQCHIP for inspiration.
Yours,
Linus Walleij
Ray Jui
maintainerRe: [PATCH v6 2/3] gpio: Cygnus: add GPIO driver
Quoted 6 lines · Linus Walleij
Quoted 4 lines · Ray Jui
This GPIO driver supports all 3 GPIO controllers in the Broadcom Cygnus SoC. The 3 GPIO controllers are 1) the ASIU GPIO controller, 2) the chipCommonG GPIO controller, and 3) the ALWAYS-ON GPIO controller
Quoted 7 lines
Quoted 2 lines
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>(Big thanks to Alexandre for doing the major part of the review, good work with following up so far!)
(...)
Yes, reviews from Alex and others are very helpful!
Quoted 29 lines
drivers/gpio/Kconfig config GPIO_74XX_MMIO · line 131
Quoted 3 lines
drivers/gpio/Kconfig +3
-0+config GPIO_BCM_CYGNUS + bool "Broadcom Cygnus GPIO support" + depends on ARCH_BCM_CYGNUS && OF_GPIOselect
GPIOLIB_IRQCHIPSee more about this below.
Quoted 21 lines
+++
b/drivers/gpio/gpio-bcm-cygnus.cdrivers/gpio/gpio-bcm-cygnus.c new file +19
-0@@ -0,0 +1,607 @@ +/* +* Copyright (C) 2014 Broadcom Corporation +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/io.h>
Quoted 9 lines
drivers/gpio/gpio-bcm-cygnus.c line 24
Quoted 5 lines
drivers/gpio/gpio-bcm-cygnus.c new file +5
-0+#include <linux/gpio.h> +#include <linux/ioport.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/irqchip/chained_irq.h> Skip <
linux/irq.h> and <linux/irqchip/chained_irq.h> as these move to the core withGPIOLIB_IRQCHIP
Will do.
Quoted 15 lines
Quoted 15 lines
drivers/gpio/gpio-bcm-cygnus.c new file +15
-0+#define CYGNUS_GPIO_DATA_IN_OFFSET 0x00 +#define CYGNUS_GPIO_DATA_OUT_OFFSET 0x04 +#define CYGNUS_GPIO_OUT_EN_OFFSET 0x08 +#define CYGNUS_GPIO_IN_TYPE_OFFSET 0x0c +#define CYGNUS_GPIO_INT_DE_OFFSET 0x10 +#define CYGNUS_GPIO_INT_EDGE_OFFSET 0x14 +#define CYGNUS_GPIO_INT_MSK_OFFSET 0x18 +#define CYGNUS_GPIO_INT_STAT_OFFSET 0x1c +#define CYGNUS_GPIO_INT_MSTAT_OFFSET 0x20 +#define CYGNUS_GPIO_INT_CLR_OFFSET 0x24 +#define CYGNUS_GPIO_PAD_RES_OFFSET 0x34 +#define CYGNUS_GPIO_RES_EN_OFFSET 0x38 + +/* drive strength control for ASIU GPIO */ +#define CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58
Quoted 9 lines
drivers/gpio/gpio-bcm-cygnus.c line 43
Quoted 3 lines
drivers/gpio/gpio-bcm-cygnus.c new file +3
-0+ +/* drive strength control for CCM GPIO */ +#define CYGNUS_GPIO_CCM_DRV0_CTRL_OFFSET 0x00This stuff (drive strength) is pin control, pin config. It does not belong in a pure GPIO driver. If you're making a combined pin control + GPIO driver, it shall be put in
drivers/pinctrl/*
Okay, I have some questions here. Are you suggesting me to register this driver to both the pinctrl subsystem and gpiolib and move it to under drivers/pinctrl/*? And obviously I should handle all pinctrl related functions (drive strength, pull up/down, and etc.) using the standard pinctrl bindings.
Or Are you suggesting me to combine this driver with the other Cygnus pinctrl driver (which only supports pinmux)?
Note in Cygnus, all pinmux logic is done in the pinmux block. And there are 3 GPIO controllers, that handle GPIO, drive strength of the GPIO pins, internal pull up/down of the GPIO pins, which are handled in this driver. So this driver is generic to all 3 GPIO controllers, as you can see from the device tree bindings, there are 3 nodes.
Therefore, I think it makes sense to have one pinmux driver that handles the pinmux block, and one generic pinctrl + gpio driver that handles functions supported by all 3 GPIO controllers. Does this make sense to you?
Quoted 35 lines
Quoted 35 lines
drivers/gpio/gpio-bcm-cygnus.c new file +35
-0+#define GPIO_BANK_SIZE 0x200 +#define NGPIOS_PER_BANK 32 +#define GPIO_BANK (pin) ((pin) / NGPIOS_PER_BANK) + +#define CYGNUS_GPIO_REG (pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg)) +#define CYGNUS_GPIO_SHIFT (pin) ((pin) % NGPIOS_PER_BANK) + +#define GPIO_FLAG_BIT_MASK 0xffff +#define GPIO_PULL_BIT_SHIFT 16 +#define GPIO_PULL_BIT_MASK 0x3 + +#define GPIO_DRV_STRENGTH_BIT_SHIFT 20 +#define GPIO_DRV_STRENGTH_BITS 3 +#define GPIO_DRV_STRENGTH_BIT_MASK ((1 << GPIO_DRV_STRENGTH_BITS) - 1) + +/* +* For GPIO internal pull up/down registers +*/ +enum gpio_pull { +GPIO_PULL_NONE =0 , +GPIO_PULL_UP , +GPIO_PULL_DOWN , +GPIO_PULL_INVALID , +}; + +/* +* GPIO drive strength +*/ +enum gpio_drv_strength { +GPIO_DRV_STRENGTH_2MA =0 , +GPIO_DRV_STRENGTH_4MA , +GPIO_DRV_STRENGTH_6MA , +GPIO_DRV_STRENGTH_8MA , +GPIO_DRV_STRENGTH_10MA , +GPIO_DRV_STRENGTH_12MA ,
Quoted 9 lines
drivers/gpio/gpio-bcm-cygnus.c line 83
Quoted 4 lines
drivers/gpio/gpio-bcm-cygnus.c new file +4
-0+GPIO_DRV_STRENGTH_14MA , +GPIO_DRV_STRENGTH_16MA , + GPIO_DRV_STRENGTH_INVALID, +};All this pull up/down and drive strength is pin config for the pin control subsystem.
Yes.
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c line 93
Quoted 9 lines
drivers/gpio/gpio-bcm-cygnus.c new file +9
-0+struct cygnus_gpio { +struct device *dev; +void __iomem *base; +void __iomem *io_ctrl; +spinlock_t lock; +struct gpio_chip gc; +unsigned num_banks; +int irq; +struct irq_domain *irq_domain;
Quoted 2 lines
Skip irq and irqdomain and use
GPIOLIB_IRQCHIP
Will switch to GPIOLIB_IRQCHIP.
Quoted 14 lines
drivers/gpio/gpio-bcm-cygnus.c line 110
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+static u32 cygnus_readl (struct cygnus_gpio *cygnus_gpio,unsigned int offset) +{ +return readl (cygnus_gpio->base + offset); +} + +static void cygnus_writel (struct cygnus_gpio *cygnus_gpio, +unsigned int offset,u32 val) +{ +writel (val, cygnus_gpio->base + offset); +}I don't see the value of using these accessors over just inlining your readl/writel stuff.
Quoted 1 line
(...)
Hmmm....I can change this back to simply readl/writel
Quoted 9 lines
drivers/gpio/gpio-bcm-cygnus.c line 141
Quoted 6 lines
drivers/gpio/gpio-bcm-cygnus.c new file +6
-0+static int cygnus_gpio_to_irq (struct gpio_chip *gc,unsigned offset) +{ +struct cygnus_gpio *cygnus_gpio =to_cygnus_gpio (gc); + +return irq_find_mapping (cygnus_gpio->irq_domain, offset); +}This goes away to the core with
GPIOLIB_IRQCHIP
Okay, thanks!
Quoted 39 lines
Quoted 24 lines
drivers/gpio/gpio-bcm-cygnus.c new file +24
-0+static void cygnus_gpio_irq_handler (unsigned int irq,struct irq_desc *desc) +{ +struct cygnus_gpio *cygnus_gpio; +struct irq_chip *chip =irq_desc_get_chip (desc); +int i, bit; + +chained_irq_enter (chip, desc); + + cygnus_gpio =irq_get_handler_data (irq); + +/* go through the entire GPIO banks and handle all interrupts */ +for (i =0 ; i < cygnus_gpio->num_banks; i++) { +unsigned long val =cygnus_readl (cygnus_gpio, + (i *GPIO_BANK_SIZE ) + +CYGNUS_GPIO_INT_MSTAT_OFFSET ); + +for_each_set_bit (bit, &val,NGPIOS_PER_BANK ) { +unsigned pin =NGPIOS_PER_BANK * i + bit; +int child_irq = +cygnus_gpio_to_irq (&cygnus_gpio->gc, pin); + +/* +* Clear the interrupt before invoking the +* handler, so we do not leave any window drivers/gpio/gpio-bcm-cygnus.c line 176
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+*/ +cygnus_writel (cygnus_gpio, (i *GPIO_BANK_SIZE ) + +CYGNUS_GPIO_INT_CLR_OFFSET ,BIT (bit)); + +generic_handle_irq (child_irq); + } + } + +chained_irq_exit (chip, desc); +}Looks good, but you will need to have the struct
gpio_chip* as handler data to useGPIOLIB_IRQCHIP, so get from there to the structcygnus_gpiosomething like:
Quoted 3 lines
struct
gpio_chip*gc =irq_desc_get_handler_data(desc); structcygnus_gpio*cyg =to_cygnus_gpio(gc);
Okay thanks!
Quoted 13 lines
drivers/gpio/gpio-bcm-cygnus.c line 336
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+static int cygnus_gpio_get (struct gpio_chip *gc,unsigned gpio) +{ +struct cygnus_gpio *cygnus_gpio =to_cygnus_gpio (gc); +unsigned int offset =CYGNUS_GPIO_REG (gpio, +CYGNUS_GPIO_DATA_IN_OFFSET ); +unsigned int shift =CYGNUS_GPIO_SHIFT (gpio); +u32 val; + + val =cygnus_readl (cygnus_gpio, offset); + val = (val >> shift) &1 ;No, do this:
Quoted 5 lines
return !!(cygnus_readl(cygnus_gpio, offset) & BIT(shift));
Maybe rename the "shift" variable to "bit" or just use the macro directly in the
readl().
Will do!
Quoted 21 lines
Quoted 21 lines
drivers/gpio/gpio-bcm-cygnus.c new file +21
-0+static int cygnus_gpio_irq_map (struct irq_domain *d,unsigned int irq, +irq_hw_number_t hwirq) +{ +int ret; + + ret =irq_set_chip_data (irq, d->host_data); +if (ret <0 ) +return ret; +irq_set_lockdep_class (irq, &gpio_lock_class); +irq_set_chip_and_handler (irq, &cygnus_gpio_irq_chip, + handle_simple_irq); +set_irq_flags (irq,IRQF_VALID ); + +return 0 ; +} + +static void cygnus_gpio_irq_unmap (struct irq_domain *d,unsigned int irq) +{ +irq_set_chip_and_handler (irq,NULL ,NULL ); +irq_set_chip_data (irq,NULL ); +}
Quoted 9 lines
drivers/gpio/gpio-bcm-cygnus.c line 371
Quoted 6 lines
drivers/gpio/gpio-bcm-cygnus.c new file +6
-0+ +static struct irq_domain_ops cygnus_irq_ops = { + .map = cygnus_gpio_irq_map, + .unmap = cygnus_gpio_irq_unmap, + .xlate = irq_domain_xlate_twocell, +};All this goes away with
GPIOLIB_IRQCHIP(that is what is good about it).
Great!
Quoted 5 lines
Quoted 1 line
+#ifdef
CONFIG_OF_GPIOWhat, that should be defined all the time, you depend on it in
Kconfig!
Yes. Will get rid of this
Quoted 6 lines
Quoted 2 lines
drivers/gpio/gpio-bcm-cygnus.c new file +2
-0+static void cygnus_gpio_set_pull (struct cygnus_gpio *cygnus_gpio, +unsigned gpio,enum gpio_pull pull)(...)
Quoted 2 lines
drivers/gpio/gpio-bcm-cygnus.c new file +2
-0+static void cygnus_gpio_set_strength (struct cygnus_gpio *cygnus_gpio, +unsigned gpio,enum gpio_drv_strength strength)(...)
Quoted 8 lines
drivers/gpio/gpio-bcm-cygnus.c line 448
Quoted 2 lines
drivers/gpio/gpio-bcm-cygnus.c new file +2
-0+static int cygnus_gpio_of_xlate (struct gpio_chip *gc, +const struct of_phandle_args *gpiospec,u32 *flags)NAK. This is pin control, put this in the pin control driver.
I guess the same that is part of this patch series.
(...)
Agreed.
Quoted 37 lines
Quoted 37 lines
drivers/gpio/gpio-bcm-cygnus.c new file +37
-0+static int cygnus_gpio_probe (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +struct resource *res; +struct cygnus_gpio *cygnus_gpio; +struct gpio_chip *gc; +u32 i, ngpios; +int ret; + + cygnus_gpio =devm_kzalloc (dev,sizeof (*cygnus_gpio),GFP_KERNEL ); +if (!cygnus_gpio) +return -ENOMEM ; + + cygnus_gpio->dev = dev; +platform_set_drvdata (pdev, cygnus_gpio); + +if (of_property_read_u32 (dev->of_node,"ngpios" , &ngpios)) { +dev_err (&pdev->dev,"missing ngpios DT property\n" ); +return -ENODEV ; + } + cygnus_gpio->num_banks = (ngpios +NGPIOS_PER_BANK -1 ) / +NGPIOS_PER_BANK ; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + cygnus_gpio->base =devm_ioremap_resource (dev, res); +if (IS_ERR (cygnus_gpio->base)) { +dev_err (&pdev->dev,"unable to map I/O memory\n" ); +return PTR_ERR (cygnus_gpio->base); + } + +/* +* Only certain types of Cygnus GPIO interfaces have I/O control +* registers +*/ + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (res) { + cygnus_gpio->io_ctrl =devm_ioremap_resource (dev, res);
Quoted 9 lines
drivers/gpio/gpio-bcm-cygnus.c line 527
Quoted 5 lines
drivers/gpio/gpio-bcm-cygnus.c new file +5
-0+if (IS_ERR (cygnus_gpio->io_ctrl)) { +dev_err (&pdev->dev,"unable to map I/O memory\n" ); +return PTR_ERR (cygnus_gpio->io_ctrl); + } + }This is a good indication that it's a separate piece of HW and should be a separate pin control driver.
Okay.
Quoted 12 lines
drivers/gpio/gpio-bcm-cygnus.c line 536
Quoted 9 lines
drivers/gpio/gpio-bcm-cygnus.c new file +9
-0+ +spin_lock_init (&cygnus_gpio->lock); + + gc = &cygnus_gpio->gc; + gc->base =-1 ; + gc->ngpio = ngpios; + gc->label =dev_name (dev); + gc->dev = dev; +#ifdef CONFIG_OF_GPIO You depend on this symbol.
Will get rid of it.
Quoted 46 lines
Quoted 18 lines
drivers/gpio/gpio-bcm-cygnus.c new file +18
-0+ gc->of_node = dev->of_node; + gc->of_gpio_n_cells =2 ; + gc->of_xlate = cygnus_gpio_of_xlate; +#endif + gc->direction_input = cygnus_gpio_direction_input; + gc->direction_output = cygnus_gpio_direction_output; + gc->set = cygnus_gpio_set; + gc->get = cygnus_gpio_get; + gc->to_irq = cygnus_gpio_to_irq; + + ret =gpiochip_add (gc); +if (ret <0 ) { +dev_err (&pdev->dev,"unable to add GPIO chip\n" ); +return ret; + } + +/* +* Some of the GPIO interfaces do not have interrupt wired to the main drivers/gpio/gpio-bcm-cygnus.c line 564
Quoted 10 lines
drivers/gpio/gpio-bcm-cygnus.c new file +10
-0+* processor +*/ + cygnus_gpio->irq =platform_get_irq (pdev,0 ); +if (cygnus_gpio->irq <0 ) { + ret = cygnus_gpio->irq; +if (ret == -EPROBE_DEFER ) + goto err_rm_gpiochip; + +dev_info (&pdev->dev,"no interrupt hook\n" ); + }From here:
Quoted 15 lines
drivers/gpio/gpio-bcm-cygnus.c new file +15
-0+ cygnus_gpio->irq_domain =irq_domain_add_linear (dev->of_node, + gc->ngpio, &cygnus_irq_ops, cygnus_gpio); +if (!cygnus_gpio->irq_domain) { +dev_err (&pdev->dev,"unable to allocate IRQ domain\n" ); + ret = -ENXIO ; + goto err_rm_gpiochip; + } + +for (i =0 ; i < gc->ngpio; i++) { +int irq =irq_create_mapping (cygnus_gpio->irq_domain, i); + +irq_set_lockdep_class (irq, &gpio_lock_class); +irq_set_chip_data (irq, cygnus_gpio); +irq_set_chip_and_handler (irq, &cygnus_gpio_irq_chip, + handle_simple_irq);
Quoted 8 lines
drivers/gpio/gpio-bcm-cygnus.c line 585
Quoted 5 lines
drivers/gpio/gpio-bcm-cygnus.c new file +5
-0+set_irq_flags (irq,IRQF_VALID ); + } + +irq_set_chained_handler (cygnus_gpio->irq, cygnus_gpio_irq_handler); +irq_set_handler_data (cygnus_gpio->irq, cygnus_gpio);To here, replace with a single call to
gpiochip_set_chained_irqchip(chip *, irq_chip *, irq, handler)...
This is excellent! Thanks!
Quoted 6 lines
Look at other drivers using
GPIOLIB_IRQCHIPfor inspiration.Yours,
Linus Walleij
Re: [PATCH v6 2/3] gpio: Cygnus: add GPIO driver
Quoted 14 lines · Ray Jui
Quoted 13 lines · Linus Walleij
drivers/gpio/gpio-bcm-cygnus.c line 43
Quoted 5 lines · Ray Jui
drivers/gpio/gpio-bcm-cygnus.c new file +5
-0+/* drive strength control for ASIU GPIO */ +#define CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58 + +/* drive strength control for CCM GPIO */ +#define CYGNUS_GPIO_CCM_DRV0_CTRL_OFFSET 0x00This stuff (drive strength) is pin control, pin config. It does not belong in a pure GPIO driver. If you're making a combined pin control + GPIO driver, it shall be put in
drivers/pinctrl/*
Quoted 3 lines
Okay, I have some questions here. Are you suggesting me to register this driver to both the pinctrl subsystem and gpiolib and move it to under
drivers/pinctrl/*?
Either you can have a combined driver in drivers/pinctrl/* which has one probe() function calling pinctrl_register(), gpiochip_add(), gpiochip_add_pin_range(), having the gpio parts call into the pin control backend with pinctrl_request_gpio(), pinctrl_free_gpio(), pinctrl_gpio_direction_input(), pinctrl_gpio_direction_output().
Or you can split it in one driver in drivers/pinctrl/* dealing with just the pin control stuff, and another driver in drivers/gpio/* dealing with the GPIO stuff, each with one probe() function.
If they are using the same register range, the first approach is probably most intuitive. If the pin control and GPIO parts are separated in different register ranges, probably the second approach is the best.
Quoted 2 lines
Or Are you suggesting me to combine this driver with the other Cygnus pinctrl driver (which only supports pinmux)?
Depends on which hardware block the pin control-like registers belongs in. See per above.
Quoted 9 lines
Note in Cygnus, all pinmux logic is done in the pinmux block. And there are 3 GPIO controllers, that handle GPIO, drive strength of the GPIO pins, internal pull up/down of the GPIO pins, which are handled in this driver. So this driver is generic to all 3 GPIO controllers, as you can see from the device tree bindings, there are 3 nodes.
Therefore, I think it makes sense to have one pinmux driver that handles the pinmux block, and one generic pinctrl + gpio driver that handles functions supported by all 3 GPIO controllers. Does this make sense to you?
Yep.
Some hardware designs put the software-controlled biasing resistors in the GPIO block electronically connected to the actual pins, so that e.g. the biasing will be available if some MMC or whatever is using the same pins in another muxing. In such situations it's quite evident that they need to be a combined GPIO and pin controller.
I have some regrets that bolting a second pin controller to the GPIO chip make things a bit complex but it's a price we have to pay for getting some kind of generic interface.
Yours,
Linus Walleij
Ray Jui
maintainerRe: [PATCH v6 2/3] gpio: Cygnus: add GPIO driver
Quoted 61 lines · Linus Walleij
Quoted 14 lines · Ray Jui
Quoted 13 lines · Linus Walleij
drivers/gpio/gpio-bcm-cygnus.c line 43
Quoted 5 lines · Ray Jui
drivers/gpio/gpio-bcm-cygnus.c new file +5
-0+/* drive strength control for ASIU GPIO */ +#define CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58 + +/* drive strength control for CCM GPIO */ +#define CYGNUS_GPIO_CCM_DRV0_CTRL_OFFSET 0x00This stuff (drive strength) is pin control, pin config. It does not belong in a pure GPIO driver. If you're making a combined pin control + GPIO driver, it shall be put in
drivers/pinctrl/*Quoted 3 lines
Okay, I have some questions here. Are you suggesting me to register this driver to both the pinctrl subsystem and gpiolib and move it to under
drivers/pinctrl/*?Either you can have a combined driver in
drivers/pinctrl/*which has oneprobe()function callingpinctrl_register(),gpiochip_add(),gpiochip_add_pin_range(), having the gpio parts call into the pin control backend withpinctrl_request_gpio(),pinctrl_free_gpio(),pinctrl_gpio_direction_input(),pinctrl_gpio_direction_output().Or you can split it in one driver in
drivers/pinctrl/*dealing with just the pin control stuff, and another driver indrivers/gpio/*dealing with the GPIO stuff, each with oneprobe()function.If they are using the same register range, the first approach is probably most intuitive. If the pin control and GPIO parts are separated in different register ranges, probably the second approach is the best.
Quoted 2 lines
Or Are you suggesting me to combine this driver with the other Cygnus pinctrl driver (which only supports pinmux)?
Depends on which hardware block the pin control-like registers belongs in. See per above.
Quoted 9 lines
Note in Cygnus, all pinmux logic is done in the pinmux block. And there are 3 GPIO controllers, that handle GPIO, drive strength of the GPIO pins, internal pull up/down of the GPIO pins, which are handled in this driver. So this driver is generic to all 3 GPIO controllers, as you can see from the device tree bindings, there are 3 nodes.
Therefore, I think it makes sense to have one pinmux driver that handles the pinmux block, and one generic pinctrl + gpio driver that handles functions supported by all 3 GPIO controllers. Does this make sense to you?
Yep.
Some hardware designs put the software-controlled biasing resistors in the GPIO block electronically connected to the actual pins, so that e.g. the biasing will be available if some MMC or whatever is using the same pins in another muxing. In such situations it's quite evident that they need to be a combined GPIO and pin controller.
Quoted 7 lines
I have some regrets that bolting a second pin controller to the GPIO chip make things a bit complex but it's a price we have to pay for getting some kind of generic interface.
Yours,
Linus Walleij
Okay. In summary, I think both of us think the following approach makes sense in my situation:
- leave pinmux in pinctrl-bcm-cygnus.c
- leave pinctrl + gpio in pinctrl-bcm-cygnus-gpio.c under drivers/pinctrl/*
But by thinking about this more, I thought this would create duplicated pinctrl descriptors in our system, one from the pinmux driver, and the other from this pinctrl+gpio driver. That is probably undesirable?
By reviewing various drivers in the pinctrl directory, I found what pinctrl-u300.c and pinctrl-coh901.c does seems to serve as a good model for me to follow:
- pinctrl-u300.c is the pinmux driver
- pinctrl-coh901.c is the gpio+pinctrl driver
The GPIO pinctrl logic is in the coh901 block, so pinctrl-coh901.c exposed two public functions u300_gpio_config_get, u300_gpio_config_set that pinctrl-u300.c can use. The u300 populates all pinmux/pinctrl related functions into the subsystem. This way there's only one pinctrl descriptor, populated through pinctrl-u300.c.
Does that model make more sense to you?
Thanks,
Ray
Re: [PATCH v6 2/3] gpio: Cygnus: add GPIO driver
Quoted 13 lines · Ray Jui
Quoted 10 lines · Linus Walleij
Some hardware designs put the software-controlled biasing resistors in the GPIO block electronically connected to the actual pins, so that e.g. the biasing will be available if some MMC or whatever is using the same pins in another muxing. In such situations it's quite evident that they need to be a combined GPIO and pin controller.
I have some regrets that bolting a second pin controller to the GPIO chip make things a bit complex but it's a price we have to pay for getting some kind of generic interface.
Quoted 8 lines
Okay. In summary, I think both of us think the following approach makes sense in my situation:
- leave pinmux inpinctrl-bcm-cygnus.c
- leave pinctrl + gpio inpinctrl-bcm-cygnus-gpio.cunderdrivers/pinctrl/*But by thinking about this more, I thought this would create duplicated pinctrl descriptors in our system, one from the pinmux driver, and the other from this pinctrl+gpio driver. That is probably undesirable?
No, there are several systems with multiple pin controllers and the framework easily handles multiple pin controllers in the same system just as well as we handle multiple GPIO chips.
Quoted 5 lines
By reviewing various drivers in the pinctrl directory, I found what
pinctrl-u300.candpinctrl-coh901.cdoes seems to serve as a good model for me to follow:
-pinctrl-u300.cis the pinmux driver
-pinctrl-coh901.cis the gpio+pinctrl driver
Yeah, I don't know if the separation between them is as beautiful as it should be. I used it when developing the pin control subsystem.
Quoted 7 lines
The GPIO pinctrl logic is in the coh901 block, so
pinctrl-coh901.cexposed two public functionsu300_gpio_config_get,u300_gpio_config_setthatpinctrl-u300.ccan use. The u300 populates all pinmux/pinctrl related functions into the subsystem. This way there's only one pinctrl descriptor, populated throughpinctrl-u300.c.Does that model make more sense to you?
Yeah I wrote it myself so I'm maybe blind for any dumbness in the code. But I think it's kind of elegant. But it is not using the generic pinctrl device tree bindings so it's kind of oldstyle and bloated in that sense.
Yours,
Linus Walleij
Ray Jui
maintainerRe: [PATCH v6 2/3] gpio: Cygnus: add GPIO driver
Quoted 45 lines · Linus Walleij
Quoted 13 lines · Ray Jui
Quoted 10 lines · Linus Walleij
Some hardware designs put the software-controlled biasing resistors in the GPIO block electronically connected to the actual pins, so that e.g. the biasing will be available if some MMC or whatever is using the same pins in another muxing. In such situations it's quite evident that they need to be a combined GPIO and pin controller.
I have some regrets that bolting a second pin controller to the GPIO chip make things a bit complex but it's a price we have to pay for getting some kind of generic interface.
Quoted 8 lines
Okay. In summary, I think both of us think the following approach makes sense in my situation:
- leave pinmux inpinctrl-bcm-cygnus.c
- leave pinctrl + gpio inpinctrl-bcm-cygnus-gpio.cunderdrivers/pinctrl/*But by thinking about this more, I thought this would create duplicated pinctrl descriptors in our system, one from the pinmux driver, and the other from this pinctrl+gpio driver. That is probably undesirable?
No, there are several systems with multiple pin controllers and the framework easily handles multiple pin controllers in the same system just as well as we handle multiple GPIO chips.
Quoted 5 lines
By reviewing various drivers in the pinctrl directory, I found what
pinctrl-u300.candpinctrl-coh901.cdoes seems to serve as a good model for me to follow:
-pinctrl-u300.cis the pinmux driver
-pinctrl-coh901.cis the gpio+pinctrl driverYeah, I don't know if the separation between them is as beautiful as it should be. I used it when developing the pin control subsystem.
Quoted 7 lines
The GPIO pinctrl logic is in the coh901 block, so
pinctrl-coh901.cexposed two public functionsu300_gpio_config_get,u300_gpio_config_setthatpinctrl-u300.ccan use. The u300 populates all pinmux/pinctrl related functions into the subsystem. This way there's only one pinctrl descriptor, populated throughpinctrl-u300.c.Does that model make more sense to you?
Quoted 8 lines
Yeah I wrote it myself so I'm maybe blind for any dumbness in the code. But I think it's kind of elegant. But it is not using the generic pinctrl device tree bindings so it's kind of oldstyle and bloated in that sense.
Yours,
Linus Walleij
Okay. I think I have a pretty good idea of what you expect. Regarding whether or not to keep pinctrl-bcm-cygnus.c and pinctrl-bcm-cygnus-gpio.c completely independent with each other and therefore have two pinctrl in the system, I'll play with it a bit more and make a decision.
Thanks a lot for spending all these time explaining it to me. Really appreciate it!
Ray Jui
maintainerPATCH v6 3/3 ARM: dts: enable GPIO for Broadcom Cygnus
In reply to Ray JuiThis enables all 3 GPIO controllers including the ASIU GPIO, the chipcommonG GPIO, and the ALWAYS-ON GPIO, for Broadcom Cygnus SoC
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +30 -0
@@ -54,6 +54,36 @@ /include/ "bcm-cygnus-clock.dtsi" + gpio_ccm: gpio at 1800a000 { + compatible = "brcm,cygnus-gpio"; + reg = <0x1800a000 0x50>, + <0x0301d164 0x20>; + ngpios = <24>; + #gpio-cells = <2>; + gpio-controller; + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + }; + + gpio_asiu: gpio at 180a5000 { + compatible = "brcm,cygnus-gpio"; + reg = <0x180a5000 0x668>; + ngpios = <122>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; + }; + + gpio_crmu: gpio at 03024800 { + compatible = "brcm,cygnus-gpio"; + reg = <0x03024800 0x50>; + ngpios = <6>; + #gpio-cells = <2>; + gpio-controller; + no-drv-strength; + }; + amba { #address-cells = <1>; #size-cells = <1>;
Signature · 1 line
1.7.9.5
Re: [PATCH v6 0/3] Add gpio support to Broadcom Cygnus SoC
In reply to Ray JuiQuoted 6 lines · On Monday 15 December 2014 18:18:24 Ray Jui wrote:
This patchset contains the initial GPIO support for the Broadcom Cygnus SoC. Cygnus has 3 GPIO controllers: 1) the ASIU GPIO; 2) the chipCommonG GPIO; and 3) the ALWAYS-ON GPIO. All 3 types of GPIO controllers are supported by the same Cygnus GPIO driver
Looks good to me now.
Arnd
Re: [PATCH v6 0/3] Add gpio support to Broadcom Cygnus SoC
In reply to Ray JuiQuoted 4 lines · Ray Jui
This patchset contains the initial GPIO support for the Broadcom Cygnus SoC. Cygnus has 3 GPIO controllers: 1) the ASIU GPIO; 2) the chipCommonG GPIO; and 3) the ALWAYS-ON GPIO. All 3 types of GPIO controllers are supported by the same Cygnus GPIO driver
No objections for this v6. The series,
Ray Jui
maintainerv2 cover Add common clock support for Broadcom iProc architecture
In reply to a message not in the archiveThis patchset contains the initial common clock support for Broadcom's iProc family of SoCs. The iProc clock architecture comprises of various PLLs, e.g., ARMPLL, GENPLL, LCPLL0, MIPIPLL, and etc. An onboard crystal serves as the basic reference clock for these PLLs. Each PLL may have several leaf clocks. One special group of clocks is the ASIU clocks, which are dervied directly from the crystal reference clock.
This patchset also contains the basic clock support for the Broadcom Cygnus SoC, which implements the iProc clock architecture
Changes from v1:
- Separate drivers/clk/Makefile change for drivers/clk/bcm out to a standalone patch
Ray Jui (5):
clk: iproc: define Broadcom iProc clock binding
clk: iproc: add initial common clock support
clk: Change bcm clocks build dependency
clk: cygnus: add clock support for Broadcom Cygnus
ARM: dts: enable clock support for Broadcom Cygnus
arch/arm/boot/dts/bcm-cygnus-clock.dtsi | 110 +++++-- arch/arm/boot/dts/bcm-cygnus.dtsi | 2 +- brcm,iproc-clocks.txt | 178 ++++++++++++ drivers/clk/Makefile | 2 +- drivers/clk/bcm/Kconfig | 9 + drivers/clk/bcm/Makefile | 2 + drivers/clk/bcm/clk-cygnus.c | 277 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-armpll.c | 286 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-asiu.c | 275 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-clk.c | 238 +++++++++++++++ drivers/clk/bcm/clk-iproc-pll.c | 483 +++++++++++++++++++++++++++++++ drivers/clk/bcm/clk-iproc.h | 155 ++++++++++ include/dt-bindings/clock/bcm-cygnus.h | 77 +++++ 13 files changed, 2067 insertions(+), 27 deletions(-) create mode 100644 brcm,iproc-clocks.txt create mode 100644 drivers/clk/bcm/clk-cygnus.c create mode 100644 drivers/clk/bcm/clk-iproc-armpll.c create mode 100644 drivers/clk/bcm/clk-iproc-asiu.c create mode 100644 drivers/clk/bcm/clk-iproc-clk.c create mode 100644 drivers/clk/bcm/clk-iproc-pll.c create mode 100644 drivers/clk/bcm/clk-iproc.h create mode 100644 include/dt-bindings/clock/bcm-cygnus.h
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v2 1/5 clk: iproc: define Broadcom iProc clock binding
Document the device tree binding for Broadcom iProc architecture based clock controller
--- brcm,iproc-clocks.txt | 178 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 brcm,iproc-clocks.txt
brcm,iproc-clocks.txt new file +178 -0
@@ -0,0 +1,178 @@ +Broadcom iProc Family Clocks + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +The iProc clock controller manages clocks that are common to the iProc family. +An SoC from the iProc family may have several PPLs, e.g., ARMPLL, GENPLL, +LCPLL0, MIPIPLL, and etc., all derived from an onboard crystal. Each PLL +comprises of several leaf clocks + +Required properties for PLLs: +- compatible: + Should have a value of the form "brcm,<soc>-<pll>". For example, GENPLL on +Cygnus has a compatible string of "brcm,cygnus-genpll" + +- #clock-cells: + Must be <0> + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for the PLL + +- clocks: + The input parent clock phandle for the PLL. For all iProc PLLs, this is an +onboard crystal with a fixed rate + +Optional Properties for PLLs: +- clock-frequency: + PLL frequency in Hz. If specified, PLL will be configured to run at +<clock-frequency> instead of the default frequency after chip reset, provided +that <clock-frequency> and its parameters are defined in the SoC specific +frequency parameter table + +Example: + + osc: oscillator { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + genpll: genpll { + #clock-cells = <0>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, + <0x0301c020 0x4>; + clocks = <&osc>; + }; + +Required properties for leaf clocks of a PLL: + +- compatible: + Should have a value of the form "brcm,<soc>-<pll>-clk". For example, leaf +clocks derived from the GENPLL on Cygnus SoC have a compatible string of +"brcm,cygnus-genpll-clk" + +- #clock-cells: + Have a value of <1> since there are more than 1 leaf clock of a +given PLL + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for the PLL leaf clocks + +- clocks: + The input parent PLL phandle for the leaf clock + +- clock-output-names: + An ordered list of strings defining the names of the leaf clocks + +Example: + + genpll: genpll { + #clock-cells = <0>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, + <0x0301c020 0x4>; + clocks = <&osc>; + }; + + genpll_clks: genpll_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-genpll-clk"; + reg = <0x0301d000 0x2c>; + clocks = <&genpll>; + clock-output-names = "axi21", "250mhz", "ihost_sys", + "enet_sw", "audio_125", "can"; + }; + +Required properties for ASIU clocks: + +ASIU clocks are a special case. These clocks are derived directly from the +reference clock of the onboard crystal + +- compatible: + Should have a value of the form "brcm,<soc>-asiu-clk". For example, ASIU +clocks for Cygnus have a compatible string of "brcm,cygnus-asiu-clk" + +- #clock-cells: + Have a value of <1> since there are more than 1 ASIU clocks + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for ASIU clocks + +- clocks: + The input parent clock phandle for the ASIU clock, i.e., the onboard +crystal + +- clock-output-names: + An ordered list of strings defining the names of the ASIU clocks + +Example: + + osc: oscillator { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + asiu_clks: asiu_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-asiu-clk"; + reg = <0x0301d048 0xc>, + <0x180aa024 0x4>; + clocks = <&osc>; + clock-output-names = "keypad", "adc/touch", "pwm"; + }; + +Cygnus +------ +PLL and leaf clock compatible strings for Cygnus are: + "brcm,cygnus-armpll" + "brcm,cygnus-genpll" + "brcm,cygnus-lcpll0" + "brcm,cygnus-mipipll" + "brcm,cygnus-genpll-clk" + "brcm,cygnus-lcpll0-clk" + "brcm,cygnus-mipipll-clk" + "brcm,cygnus-asiu-clk" + +The following table defines the set of PLL/clock index and ID for Cygnus. +These clock IDs are defined in: + "include/dt-bindings/clock/bcm-cygnus.h" + + Clock Source Index ID + --- ----- ----- --------- + crystal N/A N/A N/A + + armpll crystal N/A N/A + genpll crystal N/A N/A + lcpll0 crystal N/A N/A + mipipll crystal N/A N/A + + keypad crystal (ASIU) 0 BCM_CYGNUS_ASIU_KEYPAD_CLK + adc/tsc crystal (ASIU) 1 BCM_CYGNUS_ASIU_ADC_CLK + pwm crystal (ASIU) 2 BCM_CYGNUS_ASIU_PWM_CLK + + axi21 genpll 0 BCM_CYGNUS_GENPLL_AXI21_CLK + 250mhz genpll 1 BCM_CYGNUS_GENPLL_250MHZ_CLK + ihost_sys genpll 2 BCM_CYGNUS_GENPLL_IHOST_SYS_CLK + enet_sw genpll 3 BCM_CYGNUS_GENPLL_ENET_SW_CLK + audio_125 genpll 4 BCM_CYGNUS_GENPLL_AUDIO_125_CLK + can genpll 5 BCM_CYGNUS_GENPLL_CAN_CLK + + pcie_phy lcpll0 0 BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK + ddr_phy lcpll0 1 BCM_CYGNUS_LCPLL0_DDR_PHY_CLK + sdio lcpll0 2 BCM_CYGNUS_LCPLL0_SDIO_CLK + usb_phy lcpll0 3 BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK + smart_card lcpll0 4 BCM_CYGNUS_LCPLL0_SMART_CARD_CLK + ch5 lcpll0 5 BCM_CYGNUS_LCPLL0_CH5_UNUSED + + ch0_unused mipipll 0 BCM_CYGNUS_MIPIPLL_CH0_UNUSED + ch1_lcd mipipll 1 BCM_CYGNUS_MIPIPLL_CH1_LCD + ch2_unused mipipll 2 BCM_CYGNUS_MIPIPLL_CH2_UNUSED + ch3_unused mipipll 3 BCM_CYGNUS_MIPIPLL_CH3_UNUSED + ch4_unused mipipll 4 BCM_CYGNUS_MIPIPLL_CH4_UNUSED + ch5_unused mipipll 5 BCM_CYGNUS_MIPIPLL_CH5_UNUSED
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v2 2/5 clk: iproc: add initial common clock support
In reply to Ray JuiThis adds basic and generic support for various iProc PLLs and clocks including the ARMPLL, GENPLL, LCPLL, MIPIPLL, and ASIU clocks.
SoCs under the iProc architecture can define their specific register offsets and clock parameters for their PLL and clock controllers. These parameters can be passed as arugments into the generic iProc PLL and clock setup functions
Derived from code originally provided by Jonathan Richardson <[email protected]>
--- drivers/clk/bcm/Kconfig | 9 + drivers/clk/bcm/Makefile | 1 + drivers/clk/bcm/clk-iproc-armpll.c | 286 +++++++++++++++++++++ drivers/clk/bcm/clk-iproc-asiu.c | 275 ++++++++++++++++++++ drivers/clk/bcm/clk-iproc-clk.c | 238 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-pll.c | 483 ++++++++++++++++++++++++++++++++++++ drivers/clk/bcm/clk-iproc.h | 155 ++++++++++++ 7 files changed, 1447 insertions(+) create mode 100644 drivers/clk/bcm/clk-iproc-armpll.c create mode 100644 drivers/clk/bcm/clk-iproc-asiu.c create mode 100644 drivers/clk/bcm/clk-iproc-clk.c create mode 100644 drivers/clk/bcm/clk-iproc-pll.c create mode 100644 drivers/clk/bcm/clk-iproc.h
drivers/clk/bcm/Kconfig +9 -0
@@ -7,3 +7,12 @@ config CLK_BCM_KONA Enable common clock framework support for Broadcom SoCs using "Kona" style clock control units, including those in the BCM281xx and BCM21664 families. + +config COMMON_CLK_IPROC + bool "Broadcom iProc clock support" + depends on ARCH_BCM_IPROC + depends on COMMON_CLK + default y + help + Enable common clock framework support for Broadcom SoCs + based on the "iProc" architecture
drivers/clk/bcm/Makefile +1 -0
@@ -2,3 +2,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o +obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-clk.o clk-iproc-asiu.o
drivers/clk/bcm/clk-iproc-armpll.c new file +286 -0
286 lines not on this page · raw message
drivers/clk/bcm/clk-iproc-asiu.c new file +275 -0
275 lines not on this page · raw message
drivers/clk/bcm/clk-iproc-clk.c new file +238 -0
238 lines not on this page · raw message
drivers/clk/bcm/clk-iproc-pll.c new file +483 -0
483 lines not on this page · raw message
drivers/clk/bcm/clk-iproc.h new file +155 -0
155 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v2 3/5 clk: Change bcm clocks build dependency
In reply to Ray JuiThe clock code under drivers/clk/bcm now contains code for both the Broadcom mobile SoCs and the iProc SoCs. Change the the makefile dependency to be under config flag CONFIG_ARCH_BCM that's enabled for both families of SoCs
--- drivers/clk/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/Makefile +1 -1
@@ -41,7 +41,7 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_AT91) += at91/ -obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ +obj-$(CONFIG_ARCH_BCM) += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ obj-$(CONFIG_ARCH_HIP04) += hisilicon/
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v2 4/5 clk: cygnus: add clock support for Broadcom Cygnus
In reply to Ray JuiThe Broadcom Cygnus SoC is architected under the iProc architecture. It has the following PLLs: ARMPLL, GENPLL, LCPLL0, MIPIPLL, all dervied from an onboard crystal. Cygnus also has various ASIU clocks that are derived directly from the onboard crystal.
--- drivers/clk/bcm/Makefile | 1 + drivers/clk/bcm/clk-cygnus.c | 277 ++++++++++++++++++++++++++++++++ include/dt-bindings/clock/bcm-cygnus.h | 77 +++++++++ 3 files changed, 355 insertions(+) create mode 100644 drivers/clk/bcm/clk-cygnus.c create mode 100644 include/dt-bindings/clock/bcm-cygnus.h
drivers/clk/bcm/Makefile +1 -0
@@ -3,3 +3,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-clk.o clk-iproc-asiu.o +obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
drivers/clk/bcm/clk-cygnus.c new file +277 -0
277 lines not on this page · raw message
include/dt-bindings/clock/bcm-cygnus.h new file +77 -0
77 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v2 4/5] clk: cygnus: add clock support for Broadcom Cygnus
Quoted 22 lines · On Monday 05 January 2015 15:21:15 Ray Jui wrote:
drivers/clk/bcm/clk-cygnus.c new file +22
-0+static const struct iproc_clk_ctrl mipipll_clk[BCM_CYGNUS_NUM_MIPIPLL_CLKS ] = { + [BCM_CYGNUS_MIPIPLL_CH0_UNUSED ] = { + .channel =BCM_CYGNUS_MIPIPLL_CH0_UNUSED , + .enable =enable_val (0x4 ,12 ,6 ,18 ), + .mdiv =reg_val (0x20 ,0 ,8 ), + }, + [BCM_CYGNUS_MIPIPLL_CH1_LCD ] = { + .channel =BCM_CYGNUS_MIPIPLL_CH1_LCD , + .enable =enable_val (0x4 ,13 ,7 ,19 ), + .mdiv =reg_val (0x20 ,10 ,8 ), + }, + [BCM_CYGNUS_MIPIPLL_CH2_UNUSED ] = { + .channel =BCM_CYGNUS_MIPIPLL_CH2_UNUSED , + .enable =enable_val (0x4 ,14 ,8 ,20 ), + .mdiv =reg_val (0x20 ,20 ,8 ), + }, + [BCM_CYGNUS_MIPIPLL_CH3_UNUSED ] = { + .channel =BCM_CYGNUS_MIPIPLL_CH3_UNUSED , + .enable =enable_val (0x4 ,15 ,9 ,21 ), + .mdiv =reg_val (0x24 ,0 ,8 ), + }, + [BCM_CYGNUS_MIPIPLL_CH4_UNUSED ] = {
drivers/clk/bcm/clk-cygnus.c line 207
Quoted 10 lines
drivers/clk/bcm/clk-cygnus.c new file +10
-0+ .channel = BCM_CYGNUS_MIPIPLL_CH4_UNUSED, + .enable = enable_val(0x4, 16, 10, 22), + .mdiv = reg_val(0x24, 10, 8), + }, + [BCM_CYGNUS_MIPIPLL_CH5_UNUSED] = { + .channel = BCM_CYGNUS_MIPIPLL_CH5_UNUSED, + .enable = enable_val(0x4, 17, 11, 23), + .mdiv = reg_val(0x24, 20, 8), + }, +};
The tables look fairly regular. Is it possible that it's common to all iproc variants with a standard way to derive all other values from the channel index?
drivers/clk/bcm/clk-cygnus.c line 225
Quoted 8 lines
drivers/clk/bcm/clk-cygnus.c new file +8
-0+static const struct iproc_asiu_gate asiu_gate[BCM_CYGNUS_NUM_ASIU_CLKS ] = { + [BCM_CYGNUS_ASIU_KEYPAD_CLK ] = +asiu_gate_val (0x0 ,7 ), + [BCM_CYGNUS_ASIU_ADC_CLK ] = +asiu_gate_val (0x0 ,9 ), + [BCM_CYGNUS_ASIU_PWM_CLK ] = +asiu_gate_val (IPROC_CLK_INVALID_OFFSET ,0 ), +};
Here I think a better binding would be to pass the gate value in the clock specifier, rather than an artificial index. That would let you get rid of the BCM_CYGNUS_ASIU_KEYPAD_CLK/BCM_CYGNUS_ASIU_ADC_CLK macros.
drivers/clk/bcm/clk-cygnus.c line 231
Quoted 5 lines
drivers/clk/bcm/clk-cygnus.c new file +5
-0+static void __init cygnus_armpll_init (struct device_node *node) +{ +iproc_armpll_setup (node); +} +CLK_OF_DECLARE (cygnus_armpll,"brcm,cygnus-armpll" , cygnus_armpll_init);
How about moving all of these directly next to the tables, to keep each clock controller?
drivers/clk/bcm/clk-cygnus.c line 255
Quoted 4 lines
drivers/clk/bcm/clk-cygnus.c new file +4
-0+static void __init cygnus_genpll_clk_init (struct device_node *node) +{ +iproc_clk_setup (node, genpll_clk,BCM_CYGNUS_NUM_GENPLL_CLKS ); +}
If you use ARRAY_SIZE here, you can remove the BCM_CYGNUS_NUM_GENPLL_CLKS macro that is not useful to the DT binding.
Arnd
Ray Jui
maintainerRe: [PATCH v2 4/5] clk: cygnus: add clock support for Broadcom Cygnus
Quoted 29 lines · Arnd Bergmann
Quoted 28 lines · On Monday 05 January 2015 15:21:15 Ray Jui wrote:
drivers/clk/bcm/clk-cygnus.c new file +28
-0+static const struct iproc_clk_ctrl mipipll_clk[BCM_CYGNUS_NUM_MIPIPLL_CLKS ] = { + [BCM_CYGNUS_MIPIPLL_CH0_UNUSED ] = { + .channel =BCM_CYGNUS_MIPIPLL_CH0_UNUSED , + .enable =enable_val (0x4 ,12 ,6 ,18 ), + .mdiv =reg_val (0x20 ,0 ,8 ), + }, + [BCM_CYGNUS_MIPIPLL_CH1_LCD ] = { + .channel =BCM_CYGNUS_MIPIPLL_CH1_LCD , + .enable =enable_val (0x4 ,13 ,7 ,19 ), + .mdiv =reg_val (0x20 ,10 ,8 ), + }, + [BCM_CYGNUS_MIPIPLL_CH2_UNUSED ] = { + .channel =BCM_CYGNUS_MIPIPLL_CH2_UNUSED , + .enable =enable_val (0x4 ,14 ,8 ,20 ), + .mdiv =reg_val (0x20 ,20 ,8 ), + }, + [BCM_CYGNUS_MIPIPLL_CH3_UNUSED ] = { + .channel =BCM_CYGNUS_MIPIPLL_CH3_UNUSED , + .enable =enable_val (0x4 ,15 ,9 ,21 ), + .mdiv =reg_val (0x24 ,0 ,8 ), + }, + [BCM_CYGNUS_MIPIPLL_CH4_UNUSED ] = { + .channel =BCM_CYGNUS_MIPIPLL_CH4_UNUSED , + .enable =enable_val (0x4 ,16 ,10 ,22 ), + .mdiv =reg_val (0x24 ,10 ,8 ), + }, + [BCM_CYGNUS_MIPIPLL_CH5_UNUSED ] = { + .channel =BCM_CYGNUS_MIPIPLL_CH5_UNUSED ,
Quoted 9 lines
drivers/clk/bcm/clk-cygnus.c line 207
Quoted 4 lines
drivers/clk/bcm/clk-cygnus.c new file +4
-0+ .enable = enable_val(0x4, 17, 11, 23), + .mdiv = reg_val(0x24, 20, 8), + }, +};The tables look fairly regular. Is it possible that it's common to all iproc variants with a standard way to derive all other values from the channel index?
Ah no. Not only it's different between different iproc variants, it's also different between plls on the same soc.
Quoted 5 lines
Quoted 5 lines
drivers/clk/bcm/clk-cygnus.c new file +5
-0+static const struct iproc_asiu_gate asiu_gate[BCM_CYGNUS_NUM_ASIU_CLKS ] = { + [BCM_CYGNUS_ASIU_KEYPAD_CLK ] = +asiu_gate_val (0x0 ,7 ), + [BCM_CYGNUS_ASIU_ADC_CLK ] = +asiu_gate_val (0x0 ,9 ),
Quoted 9 lines
drivers/clk/bcm/clk-cygnus.c line 225
Quoted 3 lines
drivers/clk/bcm/clk-cygnus.c new file +3
-0+ [BCM_CYGNUS_ASIU_PWM_CLK] = + asiu_gate_val(IPROC_CLK_INVALID_OFFSET, 0), +};Here I think a better binding would be to pass the gate value in the clock specifier, rather than an artificial index. That would let you get rid of the BCM_CYGNUS_ASIU_KEYPAD_CLK/BCM_CYGNUS_ASIU_ADC_CLK macros.
You meant to pass in both the gate register offset and its bit shift through the clock specifier? But isn't the current ASIU clock code much more consistent with the rest of the iProc clock code?
Quoted 9 lines
drivers/clk/bcm/clk-cygnus.c line 231
Quoted 5 lines
drivers/clk/bcm/clk-cygnus.c new file +5
-0+static void __init cygnus_armpll_init (struct device_node *node) +{ +iproc_armpll_setup (node); +} +CLK_OF_DECLARE (cygnus_armpll,"brcm,cygnus-armpll" , cygnus_armpll_init);How about moving all of these directly next to the tables, to keep each clock controller?
Good suggestion. That would make it more clear and easier to read. Will do.
Quoted 8 lines
drivers/clk/bcm/clk-cygnus.c line 255
Quoted 4 lines
drivers/clk/bcm/clk-cygnus.c new file +4
-0+static void __init cygnus_genpll_clk_init (struct device_node *node) +{ +iproc_clk_setup (node, genpll_clk,BCM_CYGNUS_NUM_GENPLL_CLKS ); +}If you use
ARRAY_SIZEhere, you can remove theBCM_CYGNUS_NUM_GENPLL_CLKSmacro that is not useful to the DT binding.
Agreed. Will do this for all iproc clock setup calls. Thanks.
Quoted 2 lines
Arnd
Re: [PATCH v2 4/5] clk: cygnus: add clock support for Broadcom Cygnus
Quoted 9 lines · On Tuesday 06 January 2015 18:29:07 Ray Jui wrote:
Quoted 6 lines · Arnd Bergmann
On Monday 05 January 2015 15:21:15 Ray Jui wrote:
The tables look fairly regular. Is it possible that it's common to all iproc variants with a standard way to derive all other values from the channel index?
Ah no. Not only it's different between different iproc variants, it's also different between plls on the same soc.
Ok, I see.
Quoted 14 lines
Quoted 5 lines
Quoted 5 lines
drivers/clk/bcm/clk-cygnus.c new file +5
-0+static const struct iproc_asiu_gate asiu_gate[BCM_CYGNUS_NUM_ASIU_CLKS ] = { + [BCM_CYGNUS_ASIU_KEYPAD_CLK ] = +asiu_gate_val (0x0 ,7 ), + [BCM_CYGNUS_ASIU_ADC_CLK ] = +asiu_gate_val (0x0 ,9 ),Quoted 9 lines
drivers/clk/bcm/clk-cygnus.c line 225
Quoted 3 lines
drivers/clk/bcm/clk-cygnus.c new file +3
-0+ [BCM_CYGNUS_ASIU_PWM_CLK] = + asiu_gate_val(IPROC_CLK_INVALID_OFFSET, 0), +};Here I think a better binding would be to pass the gate value in the clock specifier, rather than an artificial index. That would let you get rid of the BCM_CYGNUS_ASIU_KEYPAD_CLK/BCM_CYGNUS_ASIU_ADC_CLK macros.
Quoted 3 lines
You meant to pass in both the gate register offset and its bit shift through the clock specifier? But isn't the current ASIU clock code much more consistent with the rest of the iProc clock code?
For simple devices that don't need an index macro, I would always prefer not defining them, because they are a pain to maintain. For a simple gate clock controller, we could compute both the offset and bit number from a single integer.
However, I now saw upon taking a closer look that the asiu has both a gate and a divider, and the latter one is not as simple, so my comment doesn't apply here.
Arnd
Ray Jui
maintainerRe: [PATCH v2 4/5] clk: cygnus: add clock support for Broadcom Cygnus
Quoted 26 lines · Arnd Bergmann
Quoted 16 lines · On Tuesday 06 January 2015 18:29:07 Ray Jui wrote:
Quoted 15 lines · Arnd Bergmann
drivers/clk/bcm/clk-cygnus.c line 225
Quoted 8 lines · On Monday 05 January 2015 15:21:15 Ray Jui wrote:
drivers/clk/bcm/clk-cygnus.c new file +8
-0+static const struct iproc_asiu_gate asiu_gate[BCM_CYGNUS_NUM_ASIU_CLKS ] = { + [BCM_CYGNUS_ASIU_KEYPAD_CLK ] = +asiu_gate_val (0x0 ,7 ), + [BCM_CYGNUS_ASIU_ADC_CLK ] = +asiu_gate_val (0x0 ,9 ), + [BCM_CYGNUS_ASIU_PWM_CLK ] = +asiu_gate_val (IPROC_CLK_INVALID_OFFSET ,0 ), +};Here I think a better binding would be to pass the gate value in the clock specifier, rather than an artificial index. That would let you get rid of the BCM_CYGNUS_ASIU_KEYPAD_CLK/BCM_CYGNUS_ASIU_ADC_CLK macros.
Quoted 3 lines
You meant to pass in both the gate register offset and its bit shift through the clock specifier? But isn't the current ASIU clock code much more consistent with the rest of the iProc clock code?
For simple devices that don't need an index macro, I would always prefer not defining them, because they are a pain to maintain. For a simple gate clock controller, we could compute both the offset and bit number from a single integer.
Quoted 6 lines
However, I now saw upon taking a closer look that the asiu has both a gate and a divider, and the latter one is not as simple, so my comment doesn't apply here.
Arnd
Okay. I'll leave this as it is and make other changes based on the review. Thanks!
Ray Jui
maintainerPATCH v2 5/5 ARM: dts: enable clock support for Broadcom Cygnus
In reply to Ray JuiReplace current device tree dummy clocks with real clock support for Broadcom Cygnus SoC
--- arch/arm/boot/dts/bcm-cygnus-clock.dtsi | 110 ++++++++++++++++++++++++------- arch/arm/boot/dts/bcm-cygnus.dtsi | 2 +- 2 files changed, 86 insertions(+), 26 deletions(-)
arch/arm/boot/dts/bcm-cygnus-clock.dtsi +85 -25
@@ -36,56 +36,116 @@ clocks { ranges; osc: oscillator { + #clock-cells = <0>; compatible = "fixed-clock"; - #clock-cells = <1>; clock-frequency = <25000000>; }; - apb_clk: apb_clk { - compatible = "fixed-clock"; + /* Cygnus ARM PLL */ + armpll: armpll { #clock-cells = <0>; - clock-frequency = <1000000000>; + compatible = "brcm,cygnus-armpll"; + clocks = <&osc>; + reg = <0x19000000 0x1000>; }; - periph_clk: periph_clk { - compatible = "fixed-clock"; + /* peripheral clock for system timer */ + arm_periph_clk: arm_periph_clk { #clock-cells = <0>; - clock-frequency = <500000000>; + compatible = "fixed-factor-clock"; + clocks = <&armpll>; + clock-div = <2>; + clock-mult = <1>; }; - sdio_clk: lcpll_ch2 { - compatible = "fixed-clock"; + /* APB bus clock */ + apb_clk: apb_clk { #clock-cells = <0>; - clock-frequency = <200000000>; + compatible = "fixed-factor-clock"; + clocks = <&armpll>; + clock-div = <4>; + clock-mult = <1>; }; - axi81_clk: axi81_clk { - compatible = "fixed-clock"; + genpll: genpll { #clock-cells = <0>; - clock-frequency = <100000000>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, + <0x0301c020 0x4>; + clocks = <&osc>; }; - keypad_clk: keypad_clk { - compatible = "fixed-clock"; + /* various clocks running off the GENPLL */ + genpll_clks: genpll_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-genpll-clk"; + reg = <0x0301d000 0x2c>; + clocks = <&genpll>; + clock-output-names = "axi21", "250mhz", "ihost_sys", + "enet_sw", "audio_125", "can"; + }; + + /* always 1/2 of the axi21 clock */ + axi41_clk: axi41_clk { #clock-cells = <0>; - clock-frequency = <31806>; + compatible = "fixed-factor-clock"; + clocks = <&genpll_clks 0>; + clock-div = <2>; + clock-mult = <1>; }; - adc_clk: adc_clk { - compatible = "fixed-clock"; + /* always 1/4 of the axi21 clock */ + axi81_clk: axi81_clk { #clock-cells = <0>; - clock-frequency = <1562500>; + compatible = "fixed-factor-clock"; + clocks = <&genpll_clks 0>; + clock-div = <4>; + clock-mult = <1>; }; - pwm_clk: pwm_clk { - compatible = "fixed-clock"; + lcpll0: lcpll0 { #clock-cells = <0>; - clock-frequency = <1000000>; + compatible = "brcm,cygnus-lcpll0"; + reg = <0x0301d02c 0x1c>, + <0x0301c020 0x4>; + clocks = <&osc>; }; - lcd_clk: mipipll_ch1 { - compatible = "fixed-clock"; + /* various clocks running off the LCPLL0 */ + lcpll0_clks: lcpll0_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-lcpll0-clk"; + reg = <0x0301d02c 0x1c>; + clocks = <&lcpll0>; + clock-output-names = "pcie_phy", "ddr_phy", "sdio", + "usb_phy", "smart_card", "ch5"; + }; + + mipipll: mipipll { #clock-cells = <0>; - clock-frequency = <100000000>; + compatible = "brcm,cygnus-mipipll"; + reg = <0x180a9800 0x2c>, + <0x0301c020 0x4>, + <0x180aa024 0x4>; + clock-frequency = <1350000000>; + clocks = <&osc>; + }; + + mipipll_clks: mipipll_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-mipipll-clk"; + reg = <0x180a9800 0x2c>; + clocks = <&mipipll>; + clock-output-names = "ch0_unused", "ch1_lcd", "ch2_unused", + "ch3_unused", "ch4_unused", "ch5_unused"; + }; + + asiu_clks: asiu_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-asiu-clk"; + reg = <0x0301d048 0xc>, + <0x180aa024 0x4>; + clocks = <&osc>; + clock-output-names = "keypad", "adc/touch", "pwm"; }; };
arch/arm/boot/dts/bcm-cygnus.dtsi +1 -1
@@ -134,7 +134,7 @@ compatible = "arm,cortex-a9-global-timer"; reg = <0x19020200 0x100>; interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&periph_clk>; + clocks = <&arm_periph_clk>; }; };
Signature · 1 line
1.7.9.5
Ray Jui
maintainerv3 cover Add common clock support for Broadcom iProc architecture
In reply to a message not in the archiveThis patchset contains the initial common clock support for Broadcom's iProc family of SoCs. The iProc clock architecture comprises of various PLLs, e.g., ARMPLL, GENPLL, LCPLL0, MIPIPLL, and etc. An onboard crystal serves as the basic reference clock for these PLLs. Each PLL may have several leaf clocks. One special group of clocks is the ASIU clocks, which are dervied directly from the crystal reference clock.
This patchset also contains the basic clock support for the Broadcom Cygnus SoC, which implements the iProc clock architecture
Changes from v2:
- Re-arrange Cygnus clock/pll init functions so each init function is right next to its clock table
- Removed #defines for number of clocks in Cygnus. Have the number of clocks automatically determined based on array size of the clock table
Changes from v1:
- Separate drivers/clk/Makefile change for drivers/clk/bcm out to a standalone patch
Ray Jui (5):
clk: iproc: define Broadcom iProc clock binding
clk: iproc: add initial common clock support
clk: Change bcm clocks build dependency
clk: cygnus: add clock support for Broadcom Cygnus
ARM: dts: enable clock support for Broadcom Cygnus
arch/arm/boot/dts/bcm-cygnus-clock.dtsi | 110 +++++-- arch/arm/boot/dts/bcm-cygnus.dtsi | 2 +- brcm,iproc-clocks.txt | 178 ++++++++++++ drivers/clk/Makefile | 2 +- drivers/clk/bcm/Kconfig | 9 + drivers/clk/bcm/Makefile | 2 + drivers/clk/bcm/clk-cygnus.c | 277 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-armpll.c | 286 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-asiu.c | 275 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-clk.c | 238 +++++++++++++++ drivers/clk/bcm/clk-iproc-pll.c | 483 +++++++++++++++++++++++++++++++ drivers/clk/bcm/clk-iproc.h | 155 ++++++++++ include/dt-bindings/clock/bcm-cygnus.h | 65 +++++ 13 files changed, 2055 insertions(+), 27 deletions(-) create mode 100644 brcm,iproc-clocks.txt create mode 100644 drivers/clk/bcm/clk-cygnus.c create mode 100644 drivers/clk/bcm/clk-iproc-armpll.c create mode 100644 drivers/clk/bcm/clk-iproc-asiu.c create mode 100644 drivers/clk/bcm/clk-iproc-clk.c create mode 100644 drivers/clk/bcm/clk-iproc-pll.c create mode 100644 drivers/clk/bcm/clk-iproc.h create mode 100644 include/dt-bindings/clock/bcm-cygnus.h
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v3 1/5 clk: iproc: define Broadcom iProc clock binding
Document the device tree binding for Broadcom iProc architecture based clock controller
--- brcm,iproc-clocks.txt | 178 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 brcm,iproc-clocks.txt
brcm,iproc-clocks.txt new file +178 -0
@@ -0,0 +1,178 @@ +Broadcom iProc Family Clocks + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +The iProc clock controller manages clocks that are common to the iProc family. +An SoC from the iProc family may have several PPLs, e.g., ARMPLL, GENPLL, +LCPLL0, MIPIPLL, and etc., all derived from an onboard crystal. Each PLL +comprises of several leaf clocks + +Required properties for PLLs: +- compatible: + Should have a value of the form "brcm,<soc>-<pll>". For example, GENPLL on +Cygnus has a compatible string of "brcm,cygnus-genpll" + +- #clock-cells: + Must be <0> + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for the PLL + +- clocks: + The input parent clock phandle for the PLL. For all iProc PLLs, this is an +onboard crystal with a fixed rate + +Optional Properties for PLLs: +- clock-frequency: + PLL frequency in Hz. If specified, PLL will be configured to run at +<clock-frequency> instead of the default frequency after chip reset, provided +that <clock-frequency> and its parameters are defined in the SoC specific +frequency parameter table + +Example: + + osc: oscillator { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + genpll: genpll { + #clock-cells = <0>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, + <0x0301c020 0x4>; + clocks = <&osc>; + }; + +Required properties for leaf clocks of a PLL: + +- compatible: + Should have a value of the form "brcm,<soc>-<pll>-clk". For example, leaf +clocks derived from the GENPLL on Cygnus SoC have a compatible string of +"brcm,cygnus-genpll-clk" + +- #clock-cells: + Have a value of <1> since there are more than 1 leaf clock of a +given PLL + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for the PLL leaf clocks + +- clocks: + The input parent PLL phandle for the leaf clock + +- clock-output-names: + An ordered list of strings defining the names of the leaf clocks + +Example: + + genpll: genpll { + #clock-cells = <0>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, + <0x0301c020 0x4>; + clocks = <&osc>; + }; + + genpll_clks: genpll_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-genpll-clk"; + reg = <0x0301d000 0x2c>; + clocks = <&genpll>; + clock-output-names = "axi21", "250mhz", "ihost_sys", + "enet_sw", "audio_125", "can"; + }; + +Required properties for ASIU clocks: + +ASIU clocks are a special case. These clocks are derived directly from the +reference clock of the onboard crystal + +- compatible: + Should have a value of the form "brcm,<soc>-asiu-clk". For example, ASIU +clocks for Cygnus have a compatible string of "brcm,cygnus-asiu-clk" + +- #clock-cells: + Have a value of <1> since there are more than 1 ASIU clocks + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for ASIU clocks + +- clocks: + The input parent clock phandle for the ASIU clock, i.e., the onboard +crystal + +- clock-output-names: + An ordered list of strings defining the names of the ASIU clocks + +Example: + + osc: oscillator { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + asiu_clks: asiu_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-asiu-clk"; + reg = <0x0301d048 0xc>, + <0x180aa024 0x4>; + clocks = <&osc>; + clock-output-names = "keypad", "adc/touch", "pwm"; + }; + +Cygnus +------ +PLL and leaf clock compatible strings for Cygnus are: + "brcm,cygnus-armpll" + "brcm,cygnus-genpll" + "brcm,cygnus-lcpll0" + "brcm,cygnus-mipipll" + "brcm,cygnus-genpll-clk" + "brcm,cygnus-lcpll0-clk" + "brcm,cygnus-mipipll-clk" + "brcm,cygnus-asiu-clk" + +The following table defines the set of PLL/clock index and ID for Cygnus. +These clock IDs are defined in: + "include/dt-bindings/clock/bcm-cygnus.h" + + Clock Source Index ID + --- ----- ----- --------- + crystal N/A N/A N/A + + armpll crystal N/A N/A + genpll crystal N/A N/A + lcpll0 crystal N/A N/A + mipipll crystal N/A N/A + + keypad crystal (ASIU) 0 BCM_CYGNUS_ASIU_KEYPAD_CLK + adc/tsc crystal (ASIU) 1 BCM_CYGNUS_ASIU_ADC_CLK + pwm crystal (ASIU) 2 BCM_CYGNUS_ASIU_PWM_CLK + + axi21 genpll 0 BCM_CYGNUS_GENPLL_AXI21_CLK + 250mhz genpll 1 BCM_CYGNUS_GENPLL_250MHZ_CLK + ihost_sys genpll 2 BCM_CYGNUS_GENPLL_IHOST_SYS_CLK + enet_sw genpll 3 BCM_CYGNUS_GENPLL_ENET_SW_CLK + audio_125 genpll 4 BCM_CYGNUS_GENPLL_AUDIO_125_CLK + can genpll 5 BCM_CYGNUS_GENPLL_CAN_CLK + + pcie_phy lcpll0 0 BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK + ddr_phy lcpll0 1 BCM_CYGNUS_LCPLL0_DDR_PHY_CLK + sdio lcpll0 2 BCM_CYGNUS_LCPLL0_SDIO_CLK + usb_phy lcpll0 3 BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK + smart_card lcpll0 4 BCM_CYGNUS_LCPLL0_SMART_CARD_CLK + ch5 lcpll0 5 BCM_CYGNUS_LCPLL0_CH5_UNUSED + + ch0_unused mipipll 0 BCM_CYGNUS_MIPIPLL_CH0_UNUSED + ch1_lcd mipipll 1 BCM_CYGNUS_MIPIPLL_CH1_LCD + ch2_unused mipipll 2 BCM_CYGNUS_MIPIPLL_CH2_UNUSED + ch3_unused mipipll 3 BCM_CYGNUS_MIPIPLL_CH3_UNUSED + ch4_unused mipipll 4 BCM_CYGNUS_MIPIPLL_CH4_UNUSED + ch5_unused mipipll 5 BCM_CYGNUS_MIPIPLL_CH5_UNUSED
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v3 2/5 clk: iproc: add initial common clock support
In reply to Ray JuiThis adds basic and generic support for various iProc PLLs and clocks including the ARMPLL, GENPLL, LCPLL, MIPIPLL, and ASIU clocks.
SoCs under the iProc architecture can define their specific register offsets and clock parameters for their PLL and clock controllers. These parameters can be passed as arugments into the generic iProc PLL and clock setup functions
Derived from code originally provided by Jonathan Richardson <[email protected]>
--- drivers/clk/bcm/Kconfig | 9 + drivers/clk/bcm/Makefile | 1 + drivers/clk/bcm/clk-iproc-armpll.c | 286 +++++++++++++++++++++ drivers/clk/bcm/clk-iproc-asiu.c | 275 ++++++++++++++++++++ drivers/clk/bcm/clk-iproc-clk.c | 238 ++++++++++++++++++ drivers/clk/bcm/clk-iproc-pll.c | 483 ++++++++++++++++++++++++++++++++++++ drivers/clk/bcm/clk-iproc.h | 155 ++++++++++++ 7 files changed, 1447 insertions(+) create mode 100644 drivers/clk/bcm/clk-iproc-armpll.c create mode 100644 drivers/clk/bcm/clk-iproc-asiu.c create mode 100644 drivers/clk/bcm/clk-iproc-clk.c create mode 100644 drivers/clk/bcm/clk-iproc-pll.c create mode 100644 drivers/clk/bcm/clk-iproc.h
drivers/clk/bcm/Kconfig +9 -0
@@ -7,3 +7,12 @@ config CLK_BCM_KONA Enable common clock framework support for Broadcom SoCs using "Kona" style clock control units, including those in the BCM281xx and BCM21664 families. + +config COMMON_CLK_IPROC + bool "Broadcom iProc clock support" + depends on ARCH_BCM_IPROC + depends on COMMON_CLK + default y + help + Enable common clock framework support for Broadcom SoCs + based on the "iProc" architecture
drivers/clk/bcm/Makefile +1 -0
@@ -2,3 +2,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o +obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-clk.o clk-iproc-asiu.o
drivers/clk/bcm/clk-iproc-armpll.c new file +286 -0
286 lines not on this page · raw message
drivers/clk/bcm/clk-iproc-asiu.c new file +275 -0
275 lines not on this page · raw message
drivers/clk/bcm/clk-iproc-clk.c new file +238 -0
238 lines not on this page · raw message
drivers/clk/bcm/clk-iproc-pll.c new file +483 -0
483 lines not on this page · raw message
drivers/clk/bcm/clk-iproc.h new file +155 -0
155 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v3 3/5 clk: Change bcm clocks build dependency
In reply to Ray JuiThe clock code under drivers/clk/bcm now contains code for both the Broadcom mobile SoCs and the iProc SoCs. Change the the makefile dependency to be under config flag CONFIG_ARCH_BCM that's enabled for both families of SoCs
--- drivers/clk/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/Makefile +1 -1
@@ -41,7 +41,7 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_AT91) += at91/ -obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ +obj-$(CONFIG_ARCH_BCM) += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ obj-$(CONFIG_ARCH_HIP04) += hisilicon/
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v3 4/5 clk: cygnus: add clock support for Broadcom Cygnus
In reply to Ray JuiThe Broadcom Cygnus SoC is architected under the iProc architecture. It has the following PLLs: ARMPLL, GENPLL, LCPLL0, MIPIPLL, all dervied from an onboard crystal. Cygnus also has various ASIU clocks that are derived directly from the onboard crystal.
--- drivers/clk/bcm/Makefile | 1 + drivers/clk/bcm/clk-cygnus.c | 277 ++++++++++++++++++++++++++++++++ include/dt-bindings/clock/bcm-cygnus.h | 65 ++++++++ 3 files changed, 343 insertions(+) create mode 100644 drivers/clk/bcm/clk-cygnus.c create mode 100644 include/dt-bindings/clock/bcm-cygnus.h
drivers/clk/bcm/Makefile +1 -0
@@ -3,3 +3,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-clk.o clk-iproc-asiu.o +obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
drivers/clk/bcm/clk-cygnus.c new file +277 -0
277 lines not on this page · raw message
include/dt-bindings/clock/bcm-cygnus.h new file +65 -0
65 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v3 5/5 ARM: dts: enable clock support for Broadcom Cygnus
In reply to Ray JuiReplace current device tree dummy clocks with real clock support for Broadcom Cygnus SoC
--- arch/arm/boot/dts/bcm-cygnus-clock.dtsi | 110 ++++++++++++++++++++++++------- arch/arm/boot/dts/bcm-cygnus.dtsi | 2 +- 2 files changed, 86 insertions(+), 26 deletions(-)
arch/arm/boot/dts/bcm-cygnus-clock.dtsi +85 -25
@@ -36,56 +36,116 @@ clocks { ranges; osc: oscillator { + #clock-cells = <0>; compatible = "fixed-clock"; - #clock-cells = <1>; clock-frequency = <25000000>; }; - apb_clk: apb_clk { - compatible = "fixed-clock"; + /* Cygnus ARM PLL */ + armpll: armpll { #clock-cells = <0>; - clock-frequency = <1000000000>; + compatible = "brcm,cygnus-armpll"; + clocks = <&osc>; + reg = <0x19000000 0x1000>; }; - periph_clk: periph_clk { - compatible = "fixed-clock"; + /* peripheral clock for system timer */ + arm_periph_clk: arm_periph_clk { #clock-cells = <0>; - clock-frequency = <500000000>; + compatible = "fixed-factor-clock"; + clocks = <&armpll>; + clock-div = <2>; + clock-mult = <1>; }; - sdio_clk: lcpll_ch2 { - compatible = "fixed-clock"; + /* APB bus clock */ + apb_clk: apb_clk { #clock-cells = <0>; - clock-frequency = <200000000>; + compatible = "fixed-factor-clock"; + clocks = <&armpll>; + clock-div = <4>; + clock-mult = <1>; }; - axi81_clk: axi81_clk { - compatible = "fixed-clock"; + genpll: genpll { #clock-cells = <0>; - clock-frequency = <100000000>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, + <0x0301c020 0x4>; + clocks = <&osc>; }; - keypad_clk: keypad_clk { - compatible = "fixed-clock"; + /* various clocks running off the GENPLL */ + genpll_clks: genpll_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-genpll-clk"; + reg = <0x0301d000 0x2c>; + clocks = <&genpll>; + clock-output-names = "axi21", "250mhz", "ihost_sys", + "enet_sw", "audio_125", "can"; + }; + + /* always 1/2 of the axi21 clock */ + axi41_clk: axi41_clk { #clock-cells = <0>; - clock-frequency = <31806>; + compatible = "fixed-factor-clock"; + clocks = <&genpll_clks 0>; + clock-div = <2>; + clock-mult = <1>; }; - adc_clk: adc_clk { - compatible = "fixed-clock"; + /* always 1/4 of the axi21 clock */ + axi81_clk: axi81_clk { #clock-cells = <0>; - clock-frequency = <1562500>; + compatible = "fixed-factor-clock"; + clocks = <&genpll_clks 0>; + clock-div = <4>; + clock-mult = <1>; }; - pwm_clk: pwm_clk { - compatible = "fixed-clock"; + lcpll0: lcpll0 { #clock-cells = <0>; - clock-frequency = <1000000>; + compatible = "brcm,cygnus-lcpll0"; + reg = <0x0301d02c 0x1c>, + <0x0301c020 0x4>; + clocks = <&osc>; }; - lcd_clk: mipipll_ch1 { - compatible = "fixed-clock"; + /* various clocks running off the LCPLL0 */ + lcpll0_clks: lcpll0_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-lcpll0-clk"; + reg = <0x0301d02c 0x1c>; + clocks = <&lcpll0>; + clock-output-names = "pcie_phy", "ddr_phy", "sdio", + "usb_phy", "smart_card", "ch5"; + }; + + mipipll: mipipll { #clock-cells = <0>; - clock-frequency = <100000000>; + compatible = "brcm,cygnus-mipipll"; + reg = <0x180a9800 0x2c>, + <0x0301c020 0x4>, + <0x180aa024 0x4>; + clock-frequency = <1350000000>; + clocks = <&osc>; + }; + + mipipll_clks: mipipll_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-mipipll-clk"; + reg = <0x180a9800 0x2c>; + clocks = <&mipipll>; + clock-output-names = "ch0_unused", "ch1_lcd", "ch2_unused", + "ch3_unused", "ch4_unused", "ch5_unused"; + }; + + asiu_clks: asiu_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-asiu-clk"; + reg = <0x0301d048 0xc>, + <0x180aa024 0x4>; + clocks = <&osc>; + clock-output-names = "keypad", "adc/touch", "pwm"; }; };
arch/arm/boot/dts/bcm-cygnus.dtsi +1 -1
@@ -134,7 +134,7 @@ compatible = "arm,cortex-a9-global-timer"; reg = <0x19020200 0x100>; interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&periph_clk>; + clocks = <&arm_periph_clk>; }; };
Signature · 1 line
1.7.9.5
Re: [PATCH v3 0/5] Add common clock support for Broadcom iProc architecture
In reply to Ray JuiQuoted 7 lines · On Wednesday 07 January 2015 11:22:43 Ray Jui wrote:
This patchset contains the initial common clock support for Broadcom's iProc family of SoCs. The iProc clock architecture comprises of various PLLs, e.g., ARMPLL, GENPLL, LCPLL0, MIPIPLL, and etc. An onboard crystal serves as the basic reference clock for these PLLs. Each PLL may have several leaf clocks. One special group of clocks is the ASIU clocks, which are dervied directly from the crystal reference clock.
Looks good to me now.
Arnd
Ray Jui
maintainerv4 cover Add I2C support to Broadcom iProc
In reply to a message not in the archiveThis patchset contains the initial I2C support for Broadcom iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100 kHz) and fast mode (400 kHz)
Changes from v3:
- Add config dependency to COMPILE_TEST to allow the driver to be build tested by other platforms
- Improve CPU utilization efficiency in the loop of waiting for bus to idle
- Add more comment in the driver to clarify the way how the "start busy" interrupt is triggered from the I2C controller
- Fix inconsistent coding style and format
- Improve the bus speed validation logic in the driver
- Add code to free the interrupt line in driver's remove function. Also change to use non-devm API to request the interrupt line
- Other miscellaneous improvements and fixes
Changes from v2:
- Have the I2C driver default to y so it does not need to be selected from ARCH_BCM_IPROC. This also helps to get rid of one patch. The driver still depends on ARCH_BCM_IPROC
- Get rid of redundant check on resource returned by platform_get_resource
Changes from v1:
- Fix function argument parenthesis
- Get rid of redundant driver owner field
Ray Jui (3):
i2c: iProc: define Broadcom iProc I2C binding
i2c: iproc: Add Broadcom iProc I2C Driver
ARM: dts: add I2C device nodes for Broadcom Cygnus
.../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++ arch/arm/boot/dts/bcm-cygnus.dtsi | 20 + drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 503 ++++++++++++++++++++ 5 files changed, 571 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v4 1/3 i2c: iProc: define Broadcom iProc I2C binding
Document the I2C device tree binding for Broadcom iProc family of SoCs
--- .../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt new file +37 -0
@@ -0,0 +1,37 @@ +Broadcom iProc I2C controller + +Required properties: + +- compatible: + Must be "brcm,iproc-i2c" + +- reg: + Define the base and range of the I/O address space that contain the iProc + I2C controller registers + +- interrupts: + Should contain the I2C interrupt + +- clock-frequency: + This is the I2C bus clock. Need to be either 100000 or 400000 + +- #address-cells: + Always 1 (for I2C addresses) + +- #size-cells: + Always 0 + +Example: + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + + codec: wm8750@1a { + compatible = "wlf,wm8750"; + reg = <0x1a>; + }; + };
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v4 2/3 i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Ray JuiAdd initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
--- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 503 ++++++++++++++++++++++++++++++++++++ 3 files changed, 514 insertions(+) create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
drivers/i2c/busses/Kconfig +10 -0
@@ -372,6 +372,16 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC || COMPILE_TEST + default ARCH_BCM_IPROC + help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILE
drivers/i2c/busses/Makefile +1 -0
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
drivers/i2c/busses/i2c-bcm-iproc.c new file +503 -0
503 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Hello,
drivers/i2c/busses/i2c-bcm-iproc.c line 24
Quoted 11 lines · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +11
-0+#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/delay.h>
some of them are not needed. I tested on amd64 and efm32 and could drop linux/device.h, linux/sched.h, linux/clk.h. (BTW, I wonder that you don't need clk handling.)
drivers/i2c/busses/i2c-bcm-iproc.c line 33
Quoted 2 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +2
-0+#define TIM_CFG_OFFSET 0x04 +#define TIME_CFG_MODE_400_SHIFT 31
Is the register name and the bit name prefix really different or is this a typo?
Quoted 1 line
+static int
__wait_for_bus_idle(struct bcm_iproc_i2c_dev *iproc_i2c)
A bcm_iproc_i2c prefix would be nice here.
drivers/i2c/busses/i2c-bcm-iproc.c line 149
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+static int bcm_iproc_i2c_format_addr (struct bcm_iproc_i2c_dev *iproc_i2c, +struct i2c_msg *msg,u8 *addr) +{ + +if (msg->flags &I2C_M_TEN ) { +dev_err (iproc_i2c->device,"no support for 10-bit address\n" ); +return -EINVAL ; + } + + *addr = (msg->addr <<1 );
You can also drop the parentheses.
Quoted 17 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +17
-0+switch (val) { +case M_CMD_STATUS_SUCCESS : +return 0 ; + +case M_CMD_STATUS_LOST_ARB : +dev_err (iproc_i2c->device,"lost bus arbitration\n" ); +return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_ADDR : +dev_err (iproc_i2c->device,"NAK addr:0x%02x\n" , + iproc_i2c->msg->addr); +return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_DATA : +dev_err (iproc_i2c->device,"NAK data\n" ); +return -EREMOTEIO ; +
drivers/i2c/busses/i2c-bcm-iproc.c line 190
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+case M_CMD_STATUS_TIMEOUT : +dev_err (iproc_i2c->device,"bus timeout\n" ); +return -ETIMEDOUT ; + +default : +dev_err (iproc_i2c->device,"unknown error code=%d\n" , val); +return -EREMOTEIO ; + } + +return -EREMOTEIO ;
This is not reached.
drivers/i2c/busses/i2c-bcm-iproc.c line 201
Quoted 11 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +11
-0+} + +static int bcm_iproc_i2c_xfer_single_msg (struct bcm_iproc_i2c_dev *iproc_i2c, +struct i2c_msg *msg) +{ +int ret, i; +u8 addr; +u32 val; +unsigned long time_left =msecs_to_jiffies (I2C_TIMEOUT_MESC ); + +if (msg->len <1 || msg->len >M_TX_RX_FIFO_SIZE -1 ) {
Is the < 1 a hardware or a software limitation? That means your driver doesn't support I2C_SMBUS_QUICK which is used for example by i2cdetect.
drivers/i2c/busses/i2c-bcm-iproc.c line 208
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+dev_err (iproc_i2c->device, +"supported data length is 1 - %u bytes\n" , +M_TX_RX_FIFO_SIZE -1 ); +return -EINVAL ; + } + + iproc_i2c->msg = msg;
Can it happen that iproc_i2c->msg still holds an uncompleted message here or is this serialized by the core? Wolfram? Either here something like:
if (iproc_i2c->msg) return -EBUSY;
and
iproc_i2c->msg = NULL;
when a transfer is completed is needed, or the respective code can be dropped from other drivers (e.g. i2c-efm32).
On the other hand .msg is only used in bcm_iproc_i2c_check_status() to give a diagnostic message. Maybe you can drop .msg and instead give it as an additional parameter to bcm_iproc_i2c_check_status().
drivers/i2c/busses/i2c-bcm-iproc.c line 211
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +3
-0+ ret =__wait_for_bus_idle (iproc_i2c); +if (ret) +return ret;
I would still prefer to have something like:
if (bcm_iproc_i2c_bus_busy()) return -EBUSY;
instead of a tight loop here.
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+ ret =bcm_iproc_i2c_format_addr (iproc_i2c, msg, &addr); +if (ret) +return ret; + +/* load slave address into the TX FIFO */
drivers/i2c/busses/i2c-bcm-iproc.c line 227
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+writel (addr, iproc_i2c->base +M_TX_OFFSET ); + +/* for a write transaction, load data into the TX FIFO */ +if (!(msg->flags &I2C_M_RD )) { +for (i =0 ; i < msg->len; i++) { + val = msg->buf[i]; + +/* mark the last byte */ +if (i == msg->len -1 ) + val |=1 <<M_TX_WR_STATUS_SHIFT ;
What happens if you don't mark this last byte? Could this be used to support transfers bigger than the fifo size?
drivers/i2c/busses/i2c-bcm-iproc.c line 238
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +3
-0+/* +* Enable the "start busy" interrupt, which will be triggered after +* the transaction is done, i.e., the internal start_busy bit
s/\.,/./ I think
drivers/i2c/busses/i2c-bcm-iproc.c line 239
Quoted 1 line
drivers/i2c/busses/i2c-bcm-iproc.c new file +1
-0+* transitions from 1 to 0
s/$/./
drivers/i2c/busses/i2c-bcm-iproc.c line 245
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+*/ +writel (1 <<IE_M_START_BUSY_SHIFT , iproc_i2c->base +IE_OFFSET ); + +/* +* Now we can activate the transfer. For a read operation, specify the +* number of bytes to read
s/$/./
drivers/i2c/busses/i2c-bcm-iproc.c line 256
Quoted 11 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +11
-0+*/ + val =1 <<M_CMD_START_BUSY_SHIFT ; +if (msg->flags &I2C_M_RD ) { + val |= (M_CMD_PROTOCOL_BLK_RD <<M_CMD_PROTOCOL_SHIFT ) | + (msg->len <<M_CMD_RD_CNT_SHIFT ); + }else { + val |= (M_CMD_PROTOCOL_BLK_WR <<M_CMD_PROTOCOL_SHIFT ); + } +writel (val, iproc_i2c->base +M_CMD_OFFSET ); + + time_left =wait_for_completion_timeout (&iproc_i2c->done, time_left);
When the interrupt fires here after the complete timed out and before you disable the irq you still throw the result away.
drivers/i2c/busses/i2c-bcm-iproc.c line 262
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+ +/* disable all interrupts */ +writel (0 , iproc_i2c->base +IE_OFFSET ); + +if (!time_left) { +dev_err (iproc_i2c->device,"transaction times out\n" );
s/times/timed/
drivers/i2c/busses/i2c-bcm-iproc.c line 322
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +3
-0+static uint32_t bcm_iproc_i2c_functionality (struct i2c_adapter *adap) +{ +return I2C_FUNC_I2C |I2C_FUNC_SMBUS_EMUL ;
Note that I2C_FUNC_SMBUS_EMUL includes I2C_FUNC_SMBUS_QUICK, so your driver claims to support transfers of length 0.
drivers/i2c/busses/i2c-bcm-iproc.c line 339
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+static int bcm_iproc_i2c_cfg_speed (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +unsigned int bus_speed, speed_bit; +u32 val; +int ret =of_property_read_u32 (iproc_i2c->device->of_node, +"clock-frequency" , &bus_speed); +if (ret <0 ) { +dev_err (iproc_i2c->device, +"missing clock-frequency property\n" ); +return -ENODEV ;
Is a missing property the only situation where of_property_read_u32 returns an error? Would it be sane to default to 100 kHz?
drivers/i2c/busses/i2c-bcm-iproc.c line 478
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =platform_get_drvdata (pdev); + +i2c_del_adapter (&iproc_i2c->adapter);
You need to free the irq before i2c_del_adapter.
drivers/i2c/busses/i2c-bcm-iproc.c line 486
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+free_irq (iproc_i2c->irq, iproc_i2c); +bcm_iproc_i2c_disable (iproc_i2c); + +return 0 ; +} + +static const struct of_device_id bcm_iproc_i2c_of_match[] = { + {.compatible ="brcm,iproc-i2c" ,},
Not sure this is specified to be a must, but I'd add spaces after { and before }.
drivers/i2c/busses/i2c-bcm-iproc.c line 487
Quoted 1 line
drivers/i2c/busses/i2c-bcm-iproc.c new file +1
-0+ {},
It's a good habit to write this as
{ /* sentinel */ }without trailing comma.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Re: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 4 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 208
Quoted 2 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +1
-0+ iproc_i2c->msg = msg;Can it happen that
iproc_i2c->msgstill holds an uncompleted message here or is this serialized by the core? Wolfram? Either here something
We have per-adapter locks serializing transfers, if you mean that?
Quoted 4 lines
Quoted 4 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +4
-0+static int bcm_iproc_i2c_cfg_speed (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +unsigned int bus_speed, speed_bit; +u32 val;
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 339
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+int ret =of_property_read_u32 (iproc_i2c->device->of_node, +"clock-frequency" , &bus_speed); +if (ret <0 ) { +dev_err (iproc_i2c->device, +"missing clock-frequency property\n" ); +return -ENODEV ;Is a missing property the only situation where
of_property_read_u32returns an error? Would it be sane to default to 100 kHz?
Default of 100kHz instead of -ENODEV sounds very reasonable.
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 478
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =platform_get_drvdata (pdev); + +i2c_del_adapter (&iproc_i2c->adapter);You need to free the irq before
i2c_del_adapter.
One could also keep using devm_request_irq and disable all interrupts sources here?
Thanks for the reviews, Uwe!
Wolfram
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150115/a47a65af/attachment.sig>
Re: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Hello,
Quoted 5 lines · Wolfram Sang
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 208
Quoted 1 line
drivers/i2c/busses/i2c-bcm-iproc.c new file +1
-0+ iproc_i2c->msg = msg;Can it happen that
iproc_i2c->msgstill holds an uncompleted message here or is this serialized by the core? Wolfram? Either here somethingWe have per-adapter locks serializing transfers, if you mean that?
ok, so in the efm32 driver the if (ddata->msgs) condition in efm32_i2c_master_xfer can never be true, right?
Quoted 9 lines
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 478
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =platform_get_drvdata (pdev); + +i2c_del_adapter (&iproc_i2c->adapter);You need to free the irq before
i2c_del_adapter.One could also keep using
devm_request_irqand disable all interrupts sources here?
calling devm_free_irq would work or writel(0, iproc_i2c->base + IE_OFFSET) + synchronize_irq().
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Ray Jui
maintainerRe: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Wolfram SangQuoted 10 lines · Wolfram Sang
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 478
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =platform_get_drvdata (pdev); + +i2c_del_adapter (&iproc_i2c->adapter);You need to free the irq before
i2c_del_adapter.One could also keep using
devm_request_irqand disable all interrupts sources here?
Okay this makes sense. Will use devm_request_irq and disable interrupt in the remove function. Thanks.
Quoted 4 lines
Thanks for the reviews, Uwe!
Wolfram
Ray Jui
maintainerRe: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Uwe Kleine-KönigQuoted 17 lines · Uwe Kleine-K?nig
Hello,
drivers/i2c/busses/i2c-bcm-iproc.c line 24
Quoted 11 lines · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +11
-0+#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/delay.h> some of them are not needed. I tested on amd64 and efm32 and could drop
linux/device.h,linux/sched.h,linux/clk.h. (BTW, I wonder that you don't need clk handling.)
Thanks. Will delete redundant header includes. I haven't found any clocks in Cygnus clock data sheet that are labeled i2c. I suspect the I2C clock is derived directly from the crystal and therefore we have no gating control. As you can see, the rates of 100K and 400K are set directly in the I2C block internal registers. That implies the I2C core clock is fixed.
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 33
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +2
-0+#define TIM_CFG_OFFSET 0x04 +#define TIME_CFG_MODE_400_SHIFT 31Is the register name and the bit name prefix really different or is this a typo?
Yeah, typo. Will fix.
Quoted 15 lines
Quoted 1 line
+static int
__wait_for_bus_idle(struct bcm_iproc_i2c_dev *iproc_i2c)A
bcm_iproc_i2cprefix would be nice here.drivers/i2c/busses/i2c-bcm-iproc.c line 149
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+static int bcm_iproc_i2c_format_addr (struct bcm_iproc_i2c_dev *iproc_i2c, +struct i2c_msg *msg,u8 *addr) +{ + +if (msg->flags &I2C_M_TEN ) { +dev_err (iproc_i2c->device,"no support for 10-bit address\n" ); +return -EINVAL ; + } + + *addr = (msg->addr <<1 );You can also drop the parentheses.
Yes
Quoted 20 lines
Quoted 20 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +20
-0+switch (val) { +case M_CMD_STATUS_SUCCESS : +return 0 ; + +case M_CMD_STATUS_LOST_ARB : +dev_err (iproc_i2c->device,"lost bus arbitration\n" ); +return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_ADDR : +dev_err (iproc_i2c->device,"NAK addr:0x%02x\n" , + iproc_i2c->msg->addr); +return -EREMOTEIO ; + +case M_CMD_STATUS_NACK_DATA : +dev_err (iproc_i2c->device,"NAK data\n" ); +return -EREMOTEIO ; + +case M_CMD_STATUS_TIMEOUT : +dev_err (iproc_i2c->device,"bus timeout\n" ); +return -ETIMEDOUT ;
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 190
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+ +default : +dev_err (iproc_i2c->device,"unknown error code=%d\n" , val); +return -EREMOTEIO ; + } + +return -EREMOTEIO ;This is not reached.
Will delete.
Quoted 5 lines
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+} + +static int bcm_iproc_i2c_xfer_single_msg (struct bcm_iproc_i2c_dev *iproc_i2c, +struct i2c_msg *msg) +{
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 201
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+int ret, i; +u8 addr; +u32 val; +unsigned long time_left =msecs_to_jiffies (I2C_TIMEOUT_MESC ); + +if (msg->len <1 || msg->len >M_TX_RX_FIFO_SIZE -1 ) {Is the < 1 a hardware or a software limitation? That means your driver doesn't support
I2C_SMBUS_QUICKwhich is used for example by i2cdetect.
Actually a SW issue. Will fix.
Quoted 16 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 208
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+dev_err (iproc_i2c->device, +"supported data length is 1 - %u bytes\n" , +M_TX_RX_FIFO_SIZE -1 ); +return -EINVAL ; + } + + iproc_i2c->msg = msg;Can it happen that
iproc_i2c->msgstill holds an uncompleted message here or is this serialized by the core? Wolfram? Either here something like:if (iproc_i2c->msg) return -EBUSY;and
Quoted 8 lines
iproc_i2c->msg = NULL;when a transfer is completed is needed, or the respective code can be dropped from other drivers (e.g. i2c-efm32).
On the other hand .msg is only used inbcm_iproc_i2c_check_status()to give a diagnostic message. Maybe you can drop .msg and instead give it as an additional parameter tobcm_iproc_i2c_check_status().
Yes, I'll drop .msg in iproc_i2c.
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 211
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +3
-0+ ret =__wait_for_bus_idle (iproc_i2c); +if (ret) +return ret;I would still prefer to have something like:
if (bcm_iproc_i2c_bus_busy()) return -EBUSY;instead of a tight loop here.
Okay. Will do.
Quoted 9 lines
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +9
-0+ ret =bcm_iproc_i2c_format_addr (iproc_i2c, msg, &addr); +if (ret) +return ret; + +/* load slave address into the TX FIFO */ +writel (addr, iproc_i2c->base +M_TX_OFFSET ); + +/* for a write transaction, load data into the TX FIFO */ +if (!(msg->flags &I2C_M_RD )) {
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 227
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+for (i =0 ; i < msg->len; i++) { + val = msg->buf[i]; + +/* mark the last byte */ +if (i == msg->len -1 ) + val |=1 <<M_TX_WR_STATUS_SHIFT ;What happens if you don't mark this last byte? Could this be used to support transfers bigger than the fifo size?
I do not think so. According to the iProc I2C block programming guide, one always needs to mark the last byte in a write operation.
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 238
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +3
-0+/* +* Enable the "start busy" interrupt, which will be triggered after +* the transaction is done, i.e., the internal start_busy bit s/\.,/./ I think
drivers/i2c/busses/i2c-bcm-iproc.c line 239
Quoted 1 line
drivers/i2c/busses/i2c-bcm-iproc.c new file +1
-0+* transitions from 1 to 0 s/$/./
Thanks.
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 245
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+*/ +writel (1 <<IE_M_START_BUSY_SHIFT , iproc_i2c->base +IE_OFFSET ); + +/* +* Now we can activate the transfer. For a read operation, specify the +* number of bytes to read s/$/./
Quoted 14 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 256
Quoted 11 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +11
-0+*/ + val =1 <<M_CMD_START_BUSY_SHIFT ; +if (msg->flags &I2C_M_RD ) { + val |= (M_CMD_PROTOCOL_BLK_RD <<M_CMD_PROTOCOL_SHIFT ) | + (msg->len <<M_CMD_RD_CNT_SHIFT ); + }else { + val |= (M_CMD_PROTOCOL_BLK_WR <<M_CMD_PROTOCOL_SHIFT ); + } +writel (val, iproc_i2c->base +M_CMD_OFFSET ); + + time_left =wait_for_completion_timeout (&iproc_i2c->done, time_left);When the interrupt fires here after the complete timed out and before you disable the irq you still throw the result away.
Yes, but then this comes down to the fact that if it has reached the point that is determined to be a timeout condition in the driver, one should really treat it as timeout error. In a normal condition, time_left should never reach zero.
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 262
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+ +/* disable all interrupts */ +writel (0 , iproc_i2c->base +IE_OFFSET ); + +if (!time_left) { +dev_err (iproc_i2c->device,"transaction times out\n" );s/times/timed/
Thanks.
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 322
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +3
-0+static uint32_t bcm_iproc_i2c_functionality (struct i2c_adapter *adap) +{ +return I2C_FUNC_I2C |I2C_FUNC_SMBUS_EMUL ;Note that
I2C_FUNC_SMBUS_EMULincludesI2C_FUNC_SMBUS_QUICK, so your driver claims to support transfers of length 0.
Yes. Fix the driver to support length 0 for slave address query.
Quoted 4 lines
Quoted 4 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +4
-0+static int bcm_iproc_i2c_cfg_speed (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +unsigned int bus_speed, speed_bit; +u32 val;
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 339
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+int ret =of_property_read_u32 (iproc_i2c->device->of_node, +"clock-frequency" , &bus_speed); +if (ret <0 ) { +dev_err (iproc_i2c->device, +"missing clock-frequency property\n" ); +return -ENODEV ;Is a missing property the only situation where
of_property_read_u32returns an error? Would it be sane to default to 100 kHz?
Okay, agreed with you and Wolfram. Will default to 100 KHz.
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 478
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =platform_get_drvdata (pdev); + +i2c_del_adapter (&iproc_i2c->adapter);You need to free the irq before
i2c_del_adapter.
Yes. Thanks. Change back to use devm_request_irq, and use disable_irq here before removing the adapter.
Quoted 11 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 486
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+free_irq (iproc_i2c->irq, iproc_i2c); +bcm_iproc_i2c_disable (iproc_i2c); + +return 0 ; +} + +static const struct of_device_id bcm_iproc_i2c_of_match[] = { + {.compatible ="brcm,iproc-i2c" ,},Not sure this is specified to be a must, but I'd add spaces after { and before }.
Yes.
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 487
Quoted 1 line
drivers/i2c/busses/i2c-bcm-iproc.c new file +1
-0+ {},It's a good habit to write this as
{ /* sentinel */ }without trailing comma.
Okay.
Quoted 4 lines
Best regards
Uwe
Thanks for the review!
Re: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Hello,
Quoted 16 lines · Ray Jui
Quoted 15 lines · Uwe Kleine-K?nig
drivers/i2c/busses/i2c-bcm-iproc.c line 256
Quoted 11 lines · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +11
-0+*/ + val =1 <<M_CMD_START_BUSY_SHIFT ; +if (msg->flags &I2C_M_RD ) { + val |= (M_CMD_PROTOCOL_BLK_RD <<M_CMD_PROTOCOL_SHIFT ) | + (msg->len <<M_CMD_RD_CNT_SHIFT ); + }else { + val |= (M_CMD_PROTOCOL_BLK_WR <<M_CMD_PROTOCOL_SHIFT ); + } +writel (val, iproc_i2c->base +M_CMD_OFFSET ); + + time_left =wait_for_completion_timeout (&iproc_i2c->done, time_left);When the interrupt fires here after the complete timed out and before you disable the irq you still throw the result away.
Quoted 4 lines
Yes, but then this comes down to the fact that if it has reached the point that is determined to be a timeout condition in the driver, one should really treat it as timeout error. In a normal condition,
time_leftshould never reach zero.
I don't agree here. I'm not sure there is a real technical reason, though. But still if you're in a "success after timeout already over" situation it's IMHO better to interpret it as success, not timeout.
Quoted 9 lines
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 478
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =platform_get_drvdata (pdev); + +i2c_del_adapter (&iproc_i2c->adapter);You need to free the irq before
i2c_del_adapter.Yes. Thanks. Change back to use
devm_request_irq, and usedisable_irqhere before removing the adapter.
The more lightweight approach is to set your device's irq-enable register to zero and call synchronize_irq. (For a shared irq calling disable_irq is even wrong here.)
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Ray Jui
maintainerRe: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 19 lines · Uwe Kleine-K?nig
Hello,
Quoted 16 lines · Ray Jui
Quoted 15 lines · Uwe Kleine-K?nig
drivers/i2c/busses/i2c-bcm-iproc.c line 256
Quoted 11 lines · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +11
-0+*/ + val =1 <<M_CMD_START_BUSY_SHIFT ; +if (msg->flags &I2C_M_RD ) { + val |= (M_CMD_PROTOCOL_BLK_RD <<M_CMD_PROTOCOL_SHIFT ) | + (msg->len <<M_CMD_RD_CNT_SHIFT ); + }else { + val |= (M_CMD_PROTOCOL_BLK_WR <<M_CMD_PROTOCOL_SHIFT ); + } +writel (val, iproc_i2c->base +M_CMD_OFFSET ); + + time_left =wait_for_completion_timeout (&iproc_i2c->done, time_left);When the interrupt fires here after the complete timed out and before you disable the irq you still throw the result away.
Quoted 8 lines
Quoted 4 lines
Yes, but then this comes down to the fact that if it has reached the point that is determined to be a timeout condition in the driver, one should really treat it as timeout error. In a normal condition,
time_leftshould never reach zero.I don't agree here. I'm not sure there is a real technical reason, though. But still if you're in a "success after timeout already over" situation it's IMHO better to interpret it as success, not timeout.
The thing is, the interrupt should never fire after wait_for_completion_timeout returns zero here. If it does, then the issue is really that the timeout value set in the driver is probably not long enough. I just checked other I2C drivers. I think the way how timeout is handled here is consistent with other I2C drivers.
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 478
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =platform_get_drvdata (pdev); + +i2c_del_adapter (&iproc_i2c->adapter);You need to free the irq before
i2c_del_adapter.
Quoted 6 lines
Quoted 2 lines
Yes. Thanks. Change back to use
devm_request_irq, and usedisable_irqhere before removing the adapter.The more lightweight approach is to set your device's irq-enable register to zero and call
synchronize_irq. (For a shared irq callingdisable_irqis even wrong here.)
The fact that IRQF_SHARED flag is not set indicates this is a dedicated IRQ line, so I thought using disable_irq here makes sense. But if both you and Wolfram think masking all I2C interrupts at the block level + synchronize_irq is a better approach, I can change to that. Thanks!
Quoted 3 lines
Best regards
Uwe
Re: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Hello,
Quoted 26 lines · Ray Jui
Quoted 17 lines · Uwe Kleine-K?nig
Quoted 16 lines · Ray Jui
Quoted 15 lines · Uwe Kleine-K?nig
drivers/i2c/busses/i2c-bcm-iproc.c line 256
Quoted 11 lines · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +11
-0+*/ + val =1 <<M_CMD_START_BUSY_SHIFT ; +if (msg->flags &I2C_M_RD ) { + val |= (M_CMD_PROTOCOL_BLK_RD <<M_CMD_PROTOCOL_SHIFT ) | + (msg->len <<M_CMD_RD_CNT_SHIFT ); + }else { + val |= (M_CMD_PROTOCOL_BLK_WR <<M_CMD_PROTOCOL_SHIFT ); + } +writel (val, iproc_i2c->base +M_CMD_OFFSET ); + + time_left =wait_for_completion_timeout (&iproc_i2c->done, time_left);When the interrupt fires here after the complete timed out and before you disable the irq you still throw the result away.
Quoted 8 lines
Quoted 4 lines
Yes, but then this comes down to the fact that if it has reached the point that is determined to be a timeout condition in the driver, one should really treat it as timeout error. In a normal condition,
time_leftshould never reach zero.I don't agree here. I'm not sure there is a real technical reason, though. But still if you're in a "success after timeout already over" situation it's IMHO better to interpret it as success, not timeout.
Quoted 5 lines
The thing is, the interrupt should never fire after
wait_for_completion_timeoutreturns zero here. If it does, then the issue is really that the timeout value set in the driver is probably not long enough. I just checked other I2C drivers. I think the way how timeout is handled here is consistent with other I2C drivers.
In the presence of Clock stretching there is no (theorethical) upper limit for the time needed to transfer a given message, is there? So (theoretically) you can never be sure not to interrupt an ongoing transfer.
And other drivers doing the same is only an excuse to start similar, but not to not improve :-)
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 478
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =platform_get_drvdata (pdev); + +i2c_del_adapter (&iproc_i2c->adapter);You need to free the irq before
i2c_del_adapter.Yes. Thanks. Change back to use
devm_request_irq, and usedisable_irqhere before removing the adapter.
Quoted 8 lines
Quoted 4 lines
The more lightweight approach is to set your device's irq-enable register to zero and call
synchronize_irq. (For a shared irq callingdisable_irqis even wrong here.)The fact that
IRQF_SHAREDflag is not set indicates this is a dedicated IRQ line, so I thought usingdisable_irqhere makes sense. But if both you and Wolfram think masking all I2C interrupts at the block level +synchronize_irqis a better approach, I can change to that. Thanks!
I don't care much. Using synchronize_irq is the more universal approach and so more likely correct for someone copying from your driver.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Ray Jui
maintainerRe: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 34 lines · Uwe Kleine-K?nig
Hello,
Quoted 26 lines · Ray Jui
Quoted 17 lines · Uwe Kleine-K?nig
Quoted 16 lines · Ray Jui
Quoted 15 lines · Uwe Kleine-K?nig
drivers/i2c/busses/i2c-bcm-iproc.c line 256
Quoted 11 lines · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +11
-0+*/ + val =1 <<M_CMD_START_BUSY_SHIFT ; +if (msg->flags &I2C_M_RD ) { + val |= (M_CMD_PROTOCOL_BLK_RD <<M_CMD_PROTOCOL_SHIFT ) | + (msg->len <<M_CMD_RD_CNT_SHIFT ); + }else { + val |= (M_CMD_PROTOCOL_BLK_WR <<M_CMD_PROTOCOL_SHIFT ); + } +writel (val, iproc_i2c->base +M_CMD_OFFSET ); + + time_left =wait_for_completion_timeout (&iproc_i2c->done, time_left);When the interrupt fires here after the complete timed out and before you disable the irq you still throw the result away.
Quoted 8 lines
Quoted 4 lines
Yes, but then this comes down to the fact that if it has reached the point that is determined to be a timeout condition in the driver, one should really treat it as timeout error. In a normal condition,
time_leftshould never reach zero.I don't agree here. I'm not sure there is a real technical reason, though. But still if you're in a "success after timeout already over" situation it's IMHO better to interpret it as success, not timeout.
Quoted 5 lines
The thing is, the interrupt should never fire after
wait_for_completion_timeoutreturns zero here. If it does, then the issue is really that the timeout value set in the driver is probably not long enough. I just checked other I2C drivers. I think the way how timeout is handled here is consistent with other I2C drivers.
Quoted 5 lines
In the presence of Clock stretching there is no (theorethical) upper limit for the time needed to transfer a given message, is there? So (theoretically) you can never be sure not to interrupt an ongoing transfer.
Yes. No theoretical upper limit in the case when clock is stretched by the slave. But how would adding an additional interrupt completion check below help? I assume you want the the check to be like the following?
time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);
/* disable all interrupts */
writel(0, iproc_i2c->base + IE_OFFSET);
if (!time_left && !completion_done()) {
dev_err(iproc_i2c->device, "transaction timed out\n");
/* flush FIFOs */
val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
(1 << M_FIFO_TX_FLUSH_SHIFT);
writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
return -ETIMEDOUT;
}Does the above code make sense logically? That is, wait_for_completion_timeout has timed out, and we are doing an additional check below to make sure it really has timed out?
Quoted 16 lines
And other drivers doing the same is only an excuse to start similar, but not to not improve :-)
Quoted 13 lines
Quoted 13 lines
Quoted 9 lines
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 478
Quoted 5 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +5
-0+static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =platform_get_drvdata (pdev); + +i2c_del_adapter (&iproc_i2c->adapter);You need to free the irq before
i2c_del_adapter.Yes. Thanks. Change back to use
devm_request_irq, and usedisable_irqhere before removing the adapter.The more lightweight approach is to set your device's irq-enable register to zero and call
synchronize_irq. (For a shared irq callingdisable_irqis even wrong here.)
Quoted 7 lines
Quoted 4 lines
The fact that
IRQF_SHAREDflag is not set indicates this is a dedicated IRQ line, so I thought usingdisable_irqhere makes sense. But if both you and Wolfram think masking all I2C interrupts at the block level +synchronize_irqis a better approach, I can change to that. Thanks!I don't care much. Using
synchronize_irqis the more universal approach and so more likely correct for someone copying from your driver.
Sure, more universal approach and a good example for others. It takes care of both cases of dedicated and shared interrupt. I will make that change. Thanks.
Quoted 3 lines
Best regards
Uwe
Re: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Hello,
Quoted 44 lines · Ray Jui
Quoted 34 lines · Uwe Kleine-K?nig
Hello,
Quoted 26 lines · Ray Jui
Quoted 17 lines · Uwe Kleine-K?nig
Quoted 16 lines · Ray Jui
Quoted 15 lines · Uwe Kleine-K?nig
Review
Quoted 11 lines · Ray Jui
(quoted diff) +11
-0+ */ + val = 1 << M_CMD_START_BUSY_SHIFT; + if (msg->flags & I2C_M_RD) { + val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) | + (msg->len << M_CMD_RD_CNT_SHIFT); + } else { + val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT); + } + writel(val, iproc_i2c->base + M_CMD_OFFSET); + + time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);When the interrupt fires here after the complete timed out and before you disable the irq you still throw the result away.
Quoted 8 lines
Quoted 4 lines
Yes, but then this comes down to the fact that if it has reached the point that is determined to be a timeout condition in the driver, one should really treat it as timeout error. In a normal condition,
time_leftshould never reach zero.I don't agree here. I'm not sure there is a real technical reason, though. But still if you're in a "success after timeout already over" situation it's IMHO better to interpret it as success, not timeout.
Quoted 5 lines
The thing is, the interrupt should never fire after
wait_for_completion_timeoutreturns zero here. If it does, then the issue is really that the timeout value set in the driver is probably not long enough. I just checked other I2C drivers. I think the way how timeout is handled here is consistent with other I2C drivers.Quoted 5 lines
In the presence of Clock stretching there is no (theorethical) upper limit for the time needed to transfer a given message, is there? So (theoretically) you can never be sure not to interrupt an ongoing transfer.
Yes. No theoretical upper limit in the case when clock is stretched by the slave. But how would adding an additional interrupt completion check below help? I assume you want the the check to be like the following?
Quoted 14 lines
time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);
/* disable all interrupts */
writel(0, iproc_i2c->base + IE_OFFSET);
if (!time_left && !completion_done()) {
dev_err(iproc_i2c->device, "transaction timed out\n");
/* flush FIFOs */
val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
(1 << M_FIFO_TX_FLUSH_SHIFT);
writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
return -ETIMEDOUT;
}No, I want:
time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);
if (!transfer_was_complete) {
handle_error();
...
}
handle_successful_transfer();and time_left == 0 is not a reliable indicator that the transfer failed.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Ray Jui
maintainerRe: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 73 lines · Uwe Kleine-K?nig
Hello,
Quoted 44 lines · Ray Jui
Quoted 34 lines · Uwe Kleine-K?nig
Hello,
Quoted 26 lines · Ray Jui
Quoted 17 lines · Uwe Kleine-K?nig
Quoted 16 lines · Ray Jui
Quoted 15 lines · Uwe Kleine-K?nig
Review
Quoted 11 lines · Ray Jui
(quoted diff) +11
-0+ */ + val = 1 << M_CMD_START_BUSY_SHIFT; + if (msg->flags & I2C_M_RD) { + val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) | + (msg->len << M_CMD_RD_CNT_SHIFT); + } else { + val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT); + } + writel(val, iproc_i2c->base + M_CMD_OFFSET); + + time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);When the interrupt fires here after the complete timed out and before you disable the irq you still throw the result away.
Quoted 8 lines
Quoted 4 lines
Yes, but then this comes down to the fact that if it has reached the point that is determined to be a timeout condition in the driver, one should really treat it as timeout error. In a normal condition,
time_leftshould never reach zero.I don't agree here. I'm not sure there is a real technical reason, though. But still if you're in a "success after timeout already over" situation it's IMHO better to interpret it as success, not timeout.
Quoted 5 lines
The thing is, the interrupt should never fire after
wait_for_completion_timeoutreturns zero here. If it does, then the issue is really that the timeout value set in the driver is probably not long enough. I just checked other I2C drivers. I think the way how timeout is handled here is consistent with other I2C drivers.Quoted 5 lines
In the presence of Clock stretching there is no (theorethical) upper limit for the time needed to transfer a given message, is there? So (theoretically) you can never be sure not to interrupt an ongoing transfer.
Yes. No theoretical upper limit in the case when clock is stretched by the slave. But how would adding an additional interrupt completion check below help? I assume you want the the check to be like the following?
Quoted 14 lines
time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left); /* disable all interrupts */ writel(0, iproc_i2c->base + IE_OFFSET); if (!time_left && !completion_done()) { dev_err(iproc_i2c->device, "transaction timed out\n"); /* flush FIFOs */ val = (1 << M_FIFO_RX_FLUSH_SHIFT) | (1 << M_FIFO_TX_FLUSH_SHIFT); writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET); return -ETIMEDOUT; }No, I want:
time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left); if (!transfer_was_complete) { handle_error(); ... } handle_successful_transfer();
Quoted 5 lines
and
time_left== 0 is not a reliable indicator that the transfer failed.Best regards
Uwe
Okay I'll check both time_left and transfer_was_done:
time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);
/* disable all interrupts */
writel(0, iproc_i2c->base + IE_OFFSET);
if (!time_left && !atomic_read(&iproc_i2c->transfer_is_successful)) {
dev_err(iproc_i2c->device, "transaction timed out\n");
/* flush FIFOs */
val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
(1 << M_FIFO_TX_FLUSH_SHIFT);
writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
return -ETIMEDOUT;
}Re: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 6 lines · Ray Jui
time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);
/* disable all interrupts */
writel(0, iproc_i2c->base + IE_OFFSET);
if (!time_left && !atomic_read(&iproc_i2c->transfer_is_successful)) {Why are you using atomic_read() here?
Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up according to speedtest.net.
Ray Jui
maintainerRe: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 10 lines · Russell King - ARM Linux
Quoted 6 lines · Ray Jui
time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left); /* disable all interrupts */ writel(0, iproc_i2c->base + IE_OFFSET); if (!time_left && !atomic_read(&iproc_i2c->transfer_is_successful)) {Why are you using
atomic_read()here?
transfer_is_successful 1) will be reset to 0 in this function (before kick start the I2C transfer), 2) will be set to 1 in the ISR (to signal completion of the I2C transfer), and 3) will be checked in this function here. I thought that means I should declare it volatile, because it can be modified in both the process context and interrupt context (and I use atomic because I remember Linux checkpatch warns against using volatile)?
Re: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 11 lines · Ray Jui
Quoted 8 lines · Russell King - ARM Linux
Quoted 6 lines · Ray Jui
time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left); /* disable all interrupts */ writel(0, iproc_i2c->base + IE_OFFSET); if (!time_left && !atomic_read(&iproc_i2c->transfer_is_successful)) {
Quoted 8 lines
Quoted 2 lines
Why are you using
atomic_read()here?
transfer_is_successful1) will be reset to 0 in this function (before kick start the I2C transfer), 2) will be set to 1 in the ISR (to signal completion of the I2C transfer), and 3) will be checked in this function here. I thought that means I should declare it volatile, because it can be modified in both the process context and interrupt context (and I use atomic because I remember Linux checkpatch warns against using volatile)?
You don't need volatile or atomic_t for that.
Rather than switching to atomic_t when seeing the checkpatch warning, you'd do better to read Documentation/volatile-considered-harmful.txt to understand why checkpatch issues the warning, and realise that you don't need it for the above.
Note that in the above code, the compiler can't make an assumption about iproc_i2c->transfer_is_successful because it can't tell whether a called function (eg, wait_for_completion_timeout()) could modify it.
Another possible issue with the above code are these lines:
/* disable all interrupts */ writel(0, iproc_i2c->base + IE_OFFSET);
It would be nice to think that would hit the hardware immediately, but that's making assumptions about hardware which are not necessary true. Your interrupt handler could even be running on another CPU after you've asked for that register to be written.
Depending on what you're trying to achieve here, you may need:
/* disable all interrupts */ writel(0, iproc_i2c->base + IE_OFFSET); /* read it back to ensure the write has hit */ readl(iproc_i2c->base + IE_OFFSET); /* make sure the interrupt handler isn't running */ synchronize_irq(...->irq);
if what you're trying to do is to ensure that the interrupt handler has finished running.
Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up according to speedtest.net.
Ray Jui
maintainerRe: [PATCH v4 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 23 lines · Russell King - ARM Linux
Quoted 11 lines · Ray Jui
Quoted 8 lines · Russell King - ARM Linux
Quoted 6 lines · Ray Jui
time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left); /* disable all interrupts */ writel(0, iproc_i2c->base + IE_OFFSET); if (!time_left && !atomic_read(&iproc_i2c->transfer_is_successful)) {Quoted 8 lines
Quoted 2 lines
Why are you using
atomic_read()here?
transfer_is_successful1) will be reset to 0 in this function (before kick start the I2C transfer), 2) will be set to 1 in the ISR (to signal completion of the I2C transfer), and 3) will be checked in this function here. I thought that means I should declare it volatile, because it can be modified in both the process context and interrupt context (and I use atomic because I remember Linux checkpatch warns against using volatile)?You don't need volatile or
atomic_tfor that.
Quoted 9 lines
Rather than switching to
atomic_twhen seeing the checkpatch warning, you'd do better to readDocumentation/volatile-considered-harmful.txtto understand why checkpatch issues the warning, and realise that you don't need it for the above.Note that in the above code, the compiler can't make an assumption about
iproc_i2c->transfer_is_successfulbecause it can't tell whether a called function (eg,wait_for_completion_timeout()) could modify it.
Got it. Thanks.
Quoted 20 lines
Another possible issue with the above code are these lines:
/* disable all interrupts */ writel(0, iproc_i2c->base + IE_OFFSET);It would be nice to think that would hit the hardware immediately, but that's making assumptions about hardware which are not necessary true. Your interrupt handler could even be running on another CPU after you've asked for that register to be written.
Depending on what you're trying to achieve here, you may need:
/* disable all interrupts */ writel(0, iproc_i2c->base + IE_OFFSET); /* read it back to ensure the write has hit */ readl(iproc_i2c->base + IE_OFFSET); /* make sure the interrupt handler isn't running */ synchronize_irq(...->irq);
Quoted 3 lines
if what you're trying to do is to ensure that the interrupt handler has finished running.
This will be the most robust way of handling this. Given that we've added an additional flag to check to make sure there's no interrupt missed after wait_for_completion_timeout times out, it makes sense to ensure that by the time when we check the flag there's no pending irq. I'll add this to the driver and make 'xfer_is_done' an 'int' instead of 'atomic_t'. I will also add the call to readl to flush the write in the remove function after interrupts are disabled.
Ray Jui
maintainerPATCH v4 3/3 ARM: dts: add I2C device nodes for Broadcom Cygnus
In reply to Ray JuiAdd I2C device nodes and its properties in bcm-cygnus.dtsi but keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the future
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +20 -0
@@ -70,6 +70,26 @@ }; }; + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c@1800b000 { + compatible = "brcm,iproc-i2c"; + reg = <0x1800b000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + uart0: serial@18020000 { compatible = "snps,dw-apb-uart"; reg = <0x18020000 0x100>;
Signature · 1 line
1.7.9.5
Re: [PATCH v4 3/3] ARM: dts: add I2C device nodes for Broadcom Cygnus
Hello,
Quoted 3 lines · Ray Jui
Add I2C device nodes and its properties in
bcm-cygnus.dtsibut keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the future
s/$/./
Quoted 12 lines
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- arch/arm/boot/dts/bcm-cygnus.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)arch/arm/boot/dts/bcm-cygnus.dtsi +0
-0
arch/arm/boot/dts/bcm-cygnus.dtsi line 74
Quoted 5 lines
arch/arm/boot/dts/bcm-cygnus.dtsi +2
-0@@ -70,6 +70,26 @@ }; }; + i2c0: i2c at 18008000 { + compatible = "brcm,iproc-i2c";
in patch 2 you wrote the driver is for a family of SoCs, right? Then I'd make this:
compatible = "brcm,$mysoc-iproc-i2c", "brcm,iproc-i2c";
(or maybe s/$mysoc-iproc-i2c/$mysoc-i2c/).
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Ray Jui
maintainerRe: [PATCH v4 3/3] ARM: dts: add I2C device nodes for Broadcom Cygnus
Quoted 23 lines · Uwe Kleine-K?nig
Hello,
Quoted 3 lines · Ray Jui
Add I2C device nodes and its properties in
bcm-cygnus.dtsibut keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the futures/$/./
Quoted 15 lines
Signed-off-by Ray Jui <[email protected]>Reviewed-by Scott Branden <[email protected]>--- arch/arm/boot/dts/bcm-cygnus.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)arch/arm/boot/dts/bcm-cygnus.dtsi +0
-0@@ -70,6 +70,26 @@ }; };
Quoted 7 lines
arch/arm/boot/dts/bcm-cygnus.dtsi line 74
Quoted 2 lines
arch/arm/boot/dts/bcm-cygnus.dtsi +2
-0+ i2c0: i2c at 18008000 { + compatible = "brcm,iproc-i2c";in patch 2 you wrote the driver is for a family of SoCs, right? Then I'd make this:
compatible = "brcm,$mysoc-iproc-i2c", "brcm,iproc-i2c";
Sorry could you please help to explain the intention here? Note the iProc I2C IP can be found in various iProc family of SoCs, but to my best knowledge, there hasn't been any changes of the IP in any of those SoCs.
Is the compatible ID "brcm,$mysoc-iproc-i2c" only to clarify that it's for a specific SoC? If so, what should the compatible ID array look like? Should it be changed to the following?
static const struct of_device_id bcm_iproc_i2c_of_match[] = {
{ .compatible = "brcm,iproc-i2c" },
{ .compatible = "brcm,$mysoc-iproc-i2c" },
{},
};Quoted 5 lines
(or maybe s/$mysoc-iproc-i2c/$mysoc-i2c/).
Best regards
Uwe
Re: [PATCH v4 3/3] ARM: dts: add I2C device nodes for Broadcom Cygnus
Hello,
Quoted 11 lines · Ray Jui
Quoted 7 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ i2c0: i2c at 18008000 { + compatible = "brcm,iproc-i2c";in patch 2 you wrote the driver is for a family of SoCs, right? Then I'd make this:
compatible = "brcm,$mysoc-iproc-i2c", "brcm,iproc-i2c";Sorry could you please help to explain the intention here? Note the iProc I2C IP can be found in various iProc family of SoCs, but to my best knowledge, there hasn't been any changes of the IP in any of those SoCs.
This is just for making the device tree stable in the future. Consider your gentle hardware engineers "fix" a small issue for the next generation iproc SoC "pony" that needs an incompatible software change.
Then you can fix the driver without updating the device trees by switching to the SoC specific compatible string for "pony". And in case the hardware engineers didn't tell you that there is a change and the need for the software change is only detected when the machines are already shipped, you're happy if you can fix your kernel without needing to change the bootloader that provides the dtb.
So start already today to add the (for now unused) compatible string.
Quoted 9 lines
Is the compatible ID "brcm,$mysoc-iproc-i2c" only to clarify that it's for a specific SoC? If so, what should the compatible ID array look like? Should it be changed to the following?
static const struct of_device_id bcm_iproc_i2c_of_match[] = { { .compatible = "brcm,iproc-i2c" }, { .compatible = "brcm,$mysoc-iproc-i2c" }, {}, };
No, there is no need, see above.
If something is still unclear, don't hesitate to ask.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Ray Jui
maintainerRe: [PATCH v4 3/3] ARM: dts: add I2C device nodes for Broadcom Cygnus
Quoted 35 lines · Uwe Kleine-K?nig
Hello,
Quoted 11 lines · Ray Jui
Quoted 7 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ i2c0: i2c at 18008000 { + compatible = "brcm,iproc-i2c";in patch 2 you wrote the driver is for a family of SoCs, right? Then I'd make this:
compatible = "brcm,$mysoc-iproc-i2c", "brcm,iproc-i2c";Sorry could you please help to explain the intention here? Note the iProc I2C IP can be found in various iProc family of SoCs, but to my best knowledge, there hasn't been any changes of the IP in any of those SoCs.
This is just for making the device tree stable in the future. Consider your gentle hardware engineers "fix" a small issue for the next generation iproc SoC "pony" that needs an incompatible software change.
Then you can fix the driver without updating the device trees by switching to the SoC specific compatible string for "pony". And in case the hardware engineers didn't tell you that there is a change and the need for the software change is only detected when the machines are already shipped, you're happy if you can fix your kernel without needing to change the bootloader that provides the dtb.
So start already today to add the (for now unused) compatible string.Quoted 9 lines
Is the compatible ID "brcm,$mysoc-iproc-i2c" only to clarify that it's for a specific SoC? If so, what should the compatible ID array look like? Should it be changed to the following?
static const struct of_device_id bcm_iproc_i2c_of_match[] = { { .compatible = "brcm,iproc-i2c" }, { .compatible = "brcm,$mysoc-iproc-i2c" }, {}, };
Quoted 7 lines
No, there is no need, see above.
If something is still unclear, don't hesitate to ask.
Best regards
Uwe
Okay got it. Thanks for the explanation!
Ray Jui
maintainerv5 cover Add I2C support to Broadcom iProc
In reply to a message not in the archiveThis patchset contains the initial I2C support for Broadcom iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100 kHz) and fast mode (400 kHz)
Changes from v4:
- Remove redundant header file includes
- Change the logic that waits for the host controller to be idle to simply return -EBUSY
- Use proper print level and error codes in the driver
- Allow zero length message in the driver to support I2C_SMBUS_QUICK
- Change back to use devm_request_irq. Disable interrupt in the remove function so there's no outstanding I2C interrupt when the driver is being removed from the framework
- Other minor miscellaneous improvements and fixes
Changes from v3:
- Add config dependency to COMPILE_TEST to allow the driver to be build tested by other platforms
- Improve CPU utilization efficiency in the loop of waiting for bus to idle
- Add more comment in the driver to clarify the way how the "start busy" interrupt is triggered from the I2C controller
- Fix inconsistent coding style and format
- Improve the bus speed validation logic in the driver
- Add code to free the interrupt line in driver's remove function. Also change to use non-devm API to request the interrupt line
- Other miscellaneous improvements and fixes
Changes from v2:
- Have the I2C driver default to y so it does not need to be selected from ARCH_BCM_IPROC. This also helps to get rid of one patch. The driver still depends on ARCH_BCM_IPROC
- Get rid of redundant check on resource returned by platform_get_resource
Changes from v1:
- Fix function argument parenthesis
- Get rid of redundant driver owner field
Ray Jui (3):
i2c: iProc: define Broadcom iProc I2C binding
i2c: iproc: Add Broadcom iProc I2C Driver
ARM: dts: add I2C device nodes for Broadcom Cygnus
.../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++ arch/arm/boot/dts/bcm-cygnus.dtsi | 20 + drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 493 ++++++++++++++++++++ 5 files changed, 561 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v5 1/3 i2c: iProc: define Broadcom iProc I2C binding
Document the I2C device tree binding for Broadcom iProc family of SoCs
--- .../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt new file +37 -0
@@ -0,0 +1,37 @@ +Broadcom iProc I2C controller + +Required properties: + +- compatible: + Must be "brcm,iproc-i2c" + +- reg: + Define the base and range of the I/O address space that contain the iProc + I2C controller registers + +- interrupts: + Should contain the I2C interrupt + +- clock-frequency: + This is the I2C bus clock. Need to be either 100000 or 400000 + +- #address-cells: + Always 1 (for I2C addresses) + +- #size-cells: + Always 0 + +Example: + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + + codec: wm8750@1a { + compatible = "wlf,wm8750"; + reg = <0x1a>; + }; + };
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v5 2/3 i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Ray JuiAdd initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
--- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 493 ++++++++++++++++++++++++++++++++++++ 3 files changed, 504 insertions(+) create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
drivers/i2c/busses/Kconfig +10 -0
@@ -372,6 +372,16 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC || COMPILE_TEST + default ARCH_BCM_IPROC + help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILE
drivers/i2c/busses/Makefile +1 -0
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
drivers/i2c/busses/i2c-bcm-iproc.c new file +493 -0
493 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v5 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
On 01/17/15 00:42, Ray Jui wrote:
[...]
Quoted 7 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +7
-0+/* +* Can be expanded in the future if more interrupt status bits are utilized +*/ +#define ISR_MASK (1<< IS_M_START_BUSY_SHIFT) + +static irqreturn_t bcm_iproc_i2c_isr (int irq,void *data) +{
drivers/i2c/busses/i2c-bcm-iproc.c line 114
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+struct bcm_iproc_i2c_dev *iproc_i2c = data; +u32 status =readl (iproc_i2c->base +IS_OFFSET ); + + status&=ISR_MASK ; + +if (!status) +return IRQ_NONE ; + +writel (status, iproc_i2c->base +IS_OFFSET ); +complete_all (&iproc_i2c->done);
Looking over this code it seems to me there is always a single process waiting for iproc_i2c->done to complete. So using complete() here would suffice.
Regards,
Arend
Quoted 3 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +3
-0+ +return IRQ_HANDLED ; +}
Re: [PATCH v5 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Hello,
Quoted 17 lines · Arend van Spriel
On 01/17/15 00:42, Ray Jui wrote:
[...]
Quoted 13 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +13
-0+/* +* Can be expanded in the future if more interrupt status bits are utilized +*/ +#define ISR_MASK (1<< IS_M_START_BUSY_SHIFT) + +static irqreturn_t bcm_iproc_i2c_isr (int irq,void *data) +{ +struct bcm_iproc_i2c_dev *iproc_i2c = data; +u32 status =readl (iproc_i2c->base +IS_OFFSET ); + + status&=ISR_MASK ; + +if (!status)
Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 114
Quoted 4 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +4
-0+return IRQ_NONE ; + +writel (status, iproc_i2c->base +IS_OFFSET ); +complete_all (&iproc_i2c->done);Looking over this code it seems to me there is always a single process waiting for
iproc_i2c->doneto complete. So usingcomplete()here would suffice.
Yeah, there is always only a single thread waiting. That means both complete and complete_all are suitable. AFAIK there is no reason to pick one over the other in this case.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Re: [PATCH v5 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 28 lines · Uwe Kleine-K?nig
Hello,
Quoted 17 lines · Arend van Spriel
On 01/17/15 00:42, Ray Jui wrote:
[...]
Quoted 13 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +13
-0+/* +* Can be expanded in the future if more interrupt status bits are utilized +*/ +#define ISR_MASK (1<< IS_M_START_BUSY_SHIFT) + +static irqreturn_t bcm_iproc_i2c_isr (int irq,void *data) +{ +struct bcm_iproc_i2c_dev *iproc_i2c = data; +u32 status =readl (iproc_i2c->base +IS_OFFSET ); + + status&=ISR_MASK ; + +if (!status)Quoted 8 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 114
Quoted 4 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +4
-0+return IRQ_NONE ; + +writel (status, iproc_i2c->base +IS_OFFSET ); +complete_all (&iproc_i2c->done);Looking over this code it seems to me there is always a single process waiting for
iproc_i2c->doneto complete. So usingcomplete()here would suffice.
Quoted 3 lines
Yeah, there is always only a single thread waiting. That means both complete and
complete_allare suitable. AFAIK there is no reason to pick one over the other in this case.
Clarity?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150118/ead425df/attachment-0001.sig>
Re: [PATCH v5 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Hello Wolfram,
Quoted 8 lines · Wolfram Sang
Quoted 7 lines · Uwe Kleine-K?nig
Quoted 6 lines · Arend van Spriel
drivers/i2c/busses/i2c-bcm-iproc.c line 114
Quoted 1 line · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +1
-0+complete_all (&iproc_i2c->done);Looking over this code it seems to me there is always a single process waiting for
iproc_i2c->doneto complete. So usingcomplete()here would suffice.
Quoted 5 lines
Quoted 3 lines
Yeah, there is always only a single thread waiting. That means both complete and
complete_allare suitable. AFAIK there is no reason to pick one over the other in this case.Clarity?
And which do you consider more clear? complete_all might result in the
question: "Is there >1 waiter?" and complete might yield to "What about the other waiters?". If you already know there is only one, both are on par on clarity. Might only be me?! I don't care much.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Re: [PATCH v5 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 15 lines · Uwe Kleine-K?nig
Hello Wolfram,
Quoted 12 lines · Wolfram Sang
Quoted 10 lines · Uwe Kleine-K?nig
Quoted 6 lines · Arend van Spriel
drivers/i2c/busses/i2c-bcm-iproc.c line 114
Quoted 1 line · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +1
-0+complete_all (&iproc_i2c->done);Looking over this code it seems to me there is always a single process waiting for
iproc_i2c->doneto complete. So usingcomplete()here would suffice.Yeah, there is always only a single thread waiting. That means both complete and
complete_allare suitable. AFAIK there is no reason to pick one over the other in this case.
Quoted 5 lines
Quoted 1 line
Clarity?
And which do you consider more clear?
complete_allmight result in the
question: "Is there >1 waiter?" and complete might yield to "What about the other waiters?". If you already know there is only one, both are on par on clarity. Might only be me?! I don't care much.
It is minor, I agree: If I read complete_all, I assume there is something fishy if there is only one waiter. It doesn't match. It might work, but I'll wonder if this is accidently or intentionally.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150118/29bbc836/attachment.sig>
Re: [PATCH v5 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Uwe Kleine-KönigQuoted 15 lines · Uwe Kleine-K?nig
Hello Wolfram,
Quoted 12 lines · Wolfram Sang
Quoted 10 lines · Uwe Kleine-K?nig
Quoted 6 lines · Arend van Spriel
drivers/i2c/busses/i2c-bcm-iproc.c line 114
Quoted 1 line · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +1
-0+complete_all (&iproc_i2c->done);Looking over this code it seems to me there is always a single process waiting for
iproc_i2c->doneto complete. So usingcomplete()here would suffice.Yeah, there is always only a single thread waiting. That means both complete and
complete_allare suitable. AFAIK there is no reason to pick one over the other in this case.
Quoted 5 lines
Quoted 1 line
Clarity?
And which do you consider more clear?
complete_allmight result in the
question: "Is there>1 waiter?" and complete might yield to "What about the other waiters?". If you already know there is only one, both are on par on clarity. Might only be me?! I don't care much.
Maybe it is me, but it is not about questions but it is about implicit statements that the code makes (or reader derives from it). When using complete_all you indicate to the reader "there can be more than one waiter". When using complete it indicates "there is only one waiter". If those statements are not true that is a code issue/bug.
Regards,
Arend
Quoted 3 lines
Best regards
Uwe
Re: [PATCH v5 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Hello,
Quoted 22 lines · Arend van Spriel
Quoted 15 lines · Uwe Kleine-K?nig
Hello Wolfram,
Quoted 12 lines · Wolfram Sang
Quoted 10 lines · Uwe Kleine-K?nig
Quoted 6 lines · Arend van Spriel
drivers/i2c/busses/i2c-bcm-iproc.c line 114
Quoted 1 line · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +1
-0+complete_all (&iproc_i2c->done);Looking over this code it seems to me there is always a single process waiting for
iproc_i2c->doneto complete. So usingcomplete()here would suffice.Yeah, there is always only a single thread waiting. That means both complete and
complete_allare suitable. AFAIK there is no reason to pick one over the other in this case.Quoted 5 lines
Quoted 1 line
Clarity?
And which do you consider more clear?
complete_allmight result in the
question: "Is there>1 waiter?" and complete might yield to "What about the other waiters?". If you already know there is only one, both are on par on clarity. Might only be me?! I don't care much.
Quoted 5 lines
Maybe it is me, but it is not about questions but it is about implicit statements that the code makes (or reader derives from it). When using
complete_allyou indicate to the reader "there can be more than one waiter". When using complete it indicates "there is only one waiter". If those statements are not true that is a code
No, complete works just fine in the presence of >1 waiter. It just wakes a single waiter and all others continue to wait.
That is, for single-waiter situations there is no semantic difference between complete and complete_all. But there is a difference for multi-waiter queues.
I think this is just a matter of your POV in the single-waiter
situation: complete might be intuitive because you just completed a single task and complete_all might be intuitive because it signals "I'm completely done, there is noone waiting for me any more.".
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-K?nig | Industrial Linux Solutions | http://www.pengutronix.de/ |
Re: [PATCH v5 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 25 lines · Uwe Kleine-K?nig
Hello,
Quoted 22 lines · Arend van Spriel
Quoted 20 lines · Uwe Kleine-K?nig
Hello Wolfram,
Quoted 8 lines · Wolfram Sang
Quoted 7 lines · Uwe Kleine-K?nig
Quoted 6 lines · Arend van Spriel
Review
Quoted 1 line · Ray Jui
(quoted diff) +1
-0+ complete_all(&iproc_i2c->done);Looking over this code it seems to me there is always a single process waiting for
iproc_i2c->doneto complete. So usingcomplete()here would suffice.Quoted 5 lines
Quoted 3 lines
Yeah, there is always only a single thread waiting. That means both complete and
complete_allare suitable. AFAIK there is no reason to pick one over the other in this case.Clarity?
And which do you consider more clear?
complete_allmight result in the
question: "Is there>1 waiter?" and complete might yield to "What about the other waiters?". If you already know there is only one, both are on par on clarity. Might only be me?! I don't care much.
Quoted 7 lines
Quoted 5 lines
Maybe it is me, but it is not about questions but it is about implicit statements that the code makes (or reader derives from it). When using
complete_allyou indicate to the reader "there can be more than one waiter". When using complete it indicates "there is only one waiter". If those statements are not true that is a codeNo, complete works just fine in the presence of>1 waiter. It just wakes a single waiter and all others continue to wait.
Yes. Agree.
Quoted 3 lines
That is, for single-waiter situations there is no semantic difference between complete and
complete_all. But there is a difference for multi-waiter queues.
Indeed.
Quoted 4 lines
I think this is just a matter of your POV in the single-waiter
situation: complete might be intuitive because you just completed a single task andcomplete_allmight be intuitive because it signals "I'm completely done, there is noone waiting for me any more.".
Ok. Let's leave it to the author's intuition or to say it differently "sorry for the noise" ;-)
Regards,
Arend
Quoted 3 lines
Best regards
Uwe
Ray Jui
maintainerRe: [PATCH v5 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 43 lines · Arend van Spriel
Quoted 26 lines · Uwe Kleine-K?nig
Hello,
Quoted 23 lines · Arend van Spriel
Quoted 21 lines · Uwe Kleine-K?nig
Hello Wolfram,
Quoted 8 lines · Wolfram Sang
Quoted 7 lines · Uwe Kleine-K?nig
Quoted 6 lines · Arend van Spriel
Quoted 1 line · Ray Jui
+
complete_all(&iproc_i2c->done);Looking over this code it seems to me there is always a single process waiting for
iproc_i2c->doneto complete. So usingcomplete()here would suffice.Quoted 6 lines
Quoted 4 lines
Yeah, there is always only a single thread waiting. That means both complete and
complete_allare suitable. AFAIK there is no reason to pick
one over the other in this case.Clarity?
And which do you consider more clear?
complete_allmight result in the
question: "Is there>1 waiter?" and complete might yield to "What about the other waiters?". If you already know there is only one, both are on par on clarity. Might only be me?! I don't care much.Quoted 7 lines
Quoted 5 lines
Maybe it is me, but it is not about questions but it is about implicit statements that the code makes (or reader derives from it). When using
complete_allyou indicate to the reader "there can be more than one waiter". When using complete it indicates "there is only one waiter". If those statements are not true that is a codeNo, complete works just fine in the presence of>1 waiter. It just wakes a single waiter and all others continue to wait.
Yes. Agree.
Quoted 3 lines
That is, for single-waiter situations there is no semantic difference between complete and
complete_all. But there is a difference for multi-waiter queues.Indeed.
Quoted 7 lines
Quoted 4 lines
I think this is just a matter of your POV in the single-waiter
situation: complete might be intuitive because you just completed a single task andcomplete_allmight be intuitive because it signals "I'm completely done, there is noone waiting for me any more.".Ok. Let's leave it to the author's intuition or to say it differently "sorry for the noise" ;-)
Will stay with complete_all since I meant to say "after this transfer complete interrupt, there should be no one waiting anymore (although there's currently only one waiter, and will likely stay that way)"
Thanks!
Quoted 8 lines
Regards,
ArendQuoted 3 lines
Best regards
Uwe
Ray Jui
maintainerPATCH v5 3/3 ARM: dts: add I2C device nodes for Broadcom Cygnus
In reply to Ray JuiAdd I2C device nodes and its properties in bcm-cygnus.dtsi but keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the future
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +20 -0
@@ -70,6 +70,26 @@ }; }; + i2c0: i2c at 18008000 { + compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c at 1800b000 { + compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c"; + reg = <0x1800b000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + uart0: serial at 18020000 { compatible = "snps,dw-apb-uart"; reg = <0x18020000 0x100>;
Signature · 1 line
1.7.9.5
Ray Jui
maintainerv6 cover Add I2C support to Broadcom iProc
In reply to a message not in the archiveThis patchset contains the initial I2C support for Broadcom iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100 kHz) and fast mode (400 kHz)
Changes from v5:
- Improve the "waiting for transaction to be complete" logic to take care of the corner case when an interrupt fires after wait_for_completion_timeout times out
- Improve the logic to disable I2C interrupt in the remove function. Make it more generic so it works for both dedicated and shared interrupt
Changes from v4:
- Remove redundant header file includes
- Change the logic that waits for the host controller to be idle to simply return -EBUSY
- Use proper print level and error codes in the driver
- Allow zero length message in the driver to support I2C_SMBUS_QUICK
- Change back to use devm_request_irq. Disable interrupt in the remove function so there's no outstanding I2C interrupt when the driver is being removed from the framework
- Other minor miscellaneous improvements and fixes
Changes from v3:
- Add config dependency to COMPILE_TEST to allow the driver to be build tested by other platforms
- Improve CPU utilization efficiency in the loop of waiting for bus to idle
- Add more comment in the driver to clarify the way how the "start busy" interrupt is triggered from the I2C controller
- Fix inconsistent coding style and format
- Improve the bus speed validation logic in the driver
- Add code to free the interrupt line in driver's remove function. Also change to use non-devm API to request the interrupt line
- Other miscellaneous improvements and fixes
Changes from v2:
- Have the I2C driver default to y so it does not need to be selected from ARCH_BCM_IPROC. This also helps to get rid of one patch. The driver still depends on ARCH_BCM_IPROC
- Get rid of redundant check on resource returned by platform_get_resource
Changes from v1:
- Fix function argument parenthesis
- Get rid of redundant driver owner field
Ray Jui (3):
i2c: iProc: define Broadcom iProc I2C binding
i2c: iproc: Add Broadcom iProc I2C Driver
ARM: dts: add I2C device nodes for Broadcom Cygnus
.../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++ arch/arm/boot/dts/bcm-cygnus.dtsi | 20 + drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 499 ++++++++++++++++++++ 5 files changed, 567 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v6 1/3 i2c: iProc: define Broadcom iProc I2C binding
Document the I2C device tree binding for Broadcom iProc family of SoCs
--- .../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt new file +37 -0
@@ -0,0 +1,37 @@ +Broadcom iProc I2C controller + +Required properties: + +- compatible: + Must be "brcm,iproc-i2c" + +- reg: + Define the base and range of the I/O address space that contain the iProc + I2C controller registers + +- interrupts: + Should contain the I2C interrupt + +- clock-frequency: + This is the I2C bus clock. Need to be either 100000 or 400000 + +- #address-cells: + Always 1 (for I2C addresses) + +- #size-cells: + Always 0 + +Example: + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + + codec: wm8750@1a { + compatible = "wlf,wm8750"; + reg = <0x1a>; + }; + };
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v6 2/3 i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Ray JuiAdd initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
--- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 499 ++++++++++++++++++++++++++++++++++++ 3 files changed, 510 insertions(+) create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
drivers/i2c/busses/Kconfig +10 -0
@@ -372,6 +372,16 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC || COMPILE_TEST + default ARCH_BCM_IPROC + help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILE
drivers/i2c/busses/Makefile +1 -0
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
drivers/i2c/busses/i2c-bcm-iproc.c new file +499 -0
499 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [PATCH v6 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
To see why atomic_t is pure obfuscation:
typedef struct {
int counter;
} atomic_t;So, counter is a plain int.
drivers/i2c/busses/i2c-bcm-iproc.c line 115
Quoted 12 lines · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +12
-0+static irqreturn_t bcm_iproc_i2c_isr (int irq,void *data) +{ +struct bcm_iproc_i2c_dev *iproc_i2c = data; +u32 status =readl (iproc_i2c->base +IS_OFFSET ); + + status &=ISR_MASK ; + +if (!status) +return IRQ_NONE ; + +writel (status, iproc_i2c->base +IS_OFFSET ); +atomic_set (&iproc_i2c->xfer_is_done,1 );
#define atomic_set(v,i) (((v)->counter) = (i))
So, this is the same as doing:
iproc_i2c->xfer_is_done.counter = 1;
which is merely setting the 'int' to 1.
drivers/i2c/busses/i2c-bcm-iproc.c line 254
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+ time_left =wait_for_completion_timeout (&iproc_i2c->done, time_left); + +/* disable all interrupts */ +writel (0 , iproc_i2c->base +IE_OFFSET ); + +if (!time_left && !atomic_read (&iproc_i2c->xfer_is_done)) {
#define atomic_read(v) ACCESS_ONCE((v)->counter)
This is practically the same as:
if (!time_left && !iproc_i2c->xfer_is_done.counter) {except that this access will be guaranteed to happen just once at this location (see ACCESS_ONCE() in include/linux/compiler.h).
However, complete()..wait_for_completion() ensures that there are barriers in the way: complete takes a spinlock on the waiter, so the write to iproc_i2c->xfer_is_done.counter will be visible by the time wait_for_completion() returns, and wait_for_completion() also does. The same spinlock is also manipulated by wait_for_completion(), which means there's barriers there as well, so it can't cache the value of "counter" across that call.
So, the "volatile" access guaranteed by ACCESS_ONCE() isn't even needed here.
(It would be needed if you were spinning in a loop, calling no other functions - but then you're supposed to use cpu_relax() in that circumstance, which has a compiler barrier in it, which ensures that it will re-read such a variable each time.)
Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up according to speedtest.net.
Ray Jui
maintainerRe: [PATCH v6 2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 54 lines · Russell King - ARM Linux
To see why
atomic_tis pure obfuscation:typedef struct { int counter; } atomic_t;So, counter is a plain int.
drivers/i2c/busses/i2c-bcm-iproc.c line 115
Quoted 12 lines · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +12
-0+static irqreturn_t bcm_iproc_i2c_isr (int irq,void *data) +{ +struct bcm_iproc_i2c_dev *iproc_i2c = data; +u32 status =readl (iproc_i2c->base +IS_OFFSET ); + + status &=ISR_MASK ; + +if (!status) +return IRQ_NONE ; + +writel (status, iproc_i2c->base +IS_OFFSET ); +atomic_set (&iproc_i2c->xfer_is_done,1 );#define
atomic_set(v,i)(((v)->counter) = (i))So, this is the same as doing:
iproc_i2c->xfer_is_done.counter = 1;which is merely setting the 'int' to 1.
drivers/i2c/busses/i2c-bcm-iproc.c line 254
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+ time_left =wait_for_completion_timeout (&iproc_i2c->done, time_left); + +/* disable all interrupts */ +writel (0 , iproc_i2c->base +IE_OFFSET ); + +if (!time_left && !atomic_read (&iproc_i2c->xfer_is_done)) {#define
atomic_read(v)ACCESS_ONCE((v)->counter)This is practically the same as:
if (!time_left && !iproc_i2c->xfer_is_done.counter) {except that this access will be guaranteed to happen just once at this location (see
ACCESS_ONCE()ininclude/linux/compiler.h).However, complete()..wait_for_completion() ensures that there are barriers in the way: complete takes a spinlock on the waiter, so the write to
iproc_i2c->xfer_is_done.counterwill be visible by the timewait_for_completion()returns, andwait_for_completion()also does. The same spinlock is also manipulated bywait_for_completion(), which means there's barriers there as well, so it can't cache the value of "counter" across that call.
Quoted 8 lines
So, the "volatile" access guaranteed by
ACCESS_ONCE()isn't even needed here.(It would be needed if you were spinning in a loop, calling no other functions - but then you're supposed to use
cpu_relax()in that circumstance, which has a compiler barrier in it, which ensures that it will re-read such a variable each time.)
I really learned a good lesson here. Thanks for the thorough explanation!
Ray Jui
maintainerPATCH v6 3/3 ARM: dts: add I2C device nodes for Broadcom Cygnus
In reply to Ray JuiAdd I2C device nodes and its properties in bcm-cygnus.dtsi but keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the future
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +20 -0
@@ -70,6 +70,26 @@ }; }; + i2c0: i2c@18008000 { + compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c@1800b000 { + compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c"; + reg = <0x1800b000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + uart0: serial@18020000 { compatible = "snps,dw-apb-uart"; reg = <0x18020000 0x100>;
Signature · 1 line
1.7.9.5
Ray Jui
maintainerv7 cover Add I2C support to Broadcom iProc
In reply to a message not in the archiveThis patchset contains the initial I2C support for Broadcom iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100 kHz) and fast mode (400 kHz)
Changes from v6:
- Get rid of unnecessary atomic variable usage in the driver
- Improve the "waiting for transaction to complete" logic further by making sure there's no pending/ongoing interrupt by the time when flag 'xfer_is_done' is checked
- After disabling interrupt with 'writel', add 'readl' to the same register to flush the bus to ensure the write has gone through
Changes from v5:
- Improve the "waiting for transaction to be complete" logic to take care of the corner case when an interrupt fires after wait_for_completion_timeout times out
- Improve the logic to disable I2C interrupt in the remove function. Make it more generic so it works for both dedicated and shared interrupt
Changes from v4:
- Remove redundant header file includes
- Change the logic that waits for the host controller to be idle to simply return -EBUSY
- Use proper print level and error codes in the driver
- Allow zero length message in the driver to support I2C_SMBUS_QUICK
- Change back to use devm_request_irq. Disable interrupt in the remove function so there's no outstanding I2C interrupt when the driver is being removed from the framework
- Other minor miscellaneous improvements and fixes
Changes from v3:
- Add config dependency to COMPILE_TEST to allow the driver to be build tested by other platforms
- Improve CPU utilization efficiency in the loop of waiting for bus to idle
- Add more comment in the driver to clarify the way how the "start busy" interrupt is triggered from the I2C controller
- Fix inconsistent coding style and format
- Improve the bus speed validation logic in the driver
- Add code to free the interrupt line in driver's remove function. Also change to use non-devm API to request the interrupt line
- Other miscellaneous improvements and fixes
Changes from v2:
- Have the I2C driver default to y so it does not need to be selected from ARCH_BCM_IPROC. This also helps to get rid of one patch. The driver still depends on ARCH_BCM_IPROC
- Get rid of redundant check on resource returned by platform_get_resource
Changes from v1:
- Fix function argument parenthesis
- Get rid of redundant driver owner field
Ray Jui (3):
i2c: iProc: define Broadcom iProc I2C binding
i2c: iproc: Add Broadcom iProc I2C Driver
ARM: dts: add I2C device nodes for Broadcom Cygnus
.../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++ arch/arm/boot/dts/bcm-cygnus.dtsi | 20 + drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 505 ++++++++++++++++++++ 5 files changed, 573 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v7 1/3 i2c: iProc: define Broadcom iProc I2C binding
Document the I2C device tree binding for Broadcom iProc family of SoCs
--- .../devicetree/bindings/i2c/brcm,iproc-i2c.txt | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt
Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.txt new file +37 -0
@@ -0,0 +1,37 @@ +Broadcom iProc I2C controller + +Required properties: + +- compatible: + Must be "brcm,iproc-i2c" + +- reg: + Define the base and range of the I/O address space that contain the iProc + I2C controller registers + +- interrupts: + Should contain the I2C interrupt + +- clock-frequency: + This is the I2C bus clock. Need to be either 100000 or 400000 + +- #address-cells: + Always 1 (for I2C addresses) + +- #size-cells: + Always 0 + +Example: + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + + codec: wm8750@1a { + compatible = "wlf,wm8750"; + reg = <0x1a>; + }; + };
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v7 2/3 i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Ray JuiAdd initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
--- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 505 ++++++++++++++++++++++++++++++++++++ 3 files changed, 516 insertions(+) create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.c
drivers/i2c/busses/Kconfig +10 -0
@@ -372,6 +372,16 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC || COMPILE_TEST + default ARCH_BCM_IPROC + help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILE
drivers/i2c/busses/Makefile +1 -0
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
drivers/i2c/busses/i2c-bcm-iproc.c new file +505 -0
505 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Re: [v7,2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 182 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Signed-off-by Ray Jui <rjui <at> broadcom.com>Reviewed-by Scott Branden <sbranden <at> broadcom.com>--- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 505 ++++++++++++++++++++++++++++++++++++ 3 files changed, 516 insertions(+) create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.cdrivers/i2c/busses/Kconfig +10
-0<at> <at> -372,6 +372,16 <at> <at> config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC || COMPILE_TEST + default ARCH_BCM_IPROC + help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILEdrivers/i2c/busses/Makefile +1
-0<at> <at> -33,6 +33,7 <at> <at> obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.odrivers/i2c/busses/i2c-bcm-iproc.c new file +127
-0<at> <at> -0,0 +1,505 <at> <at> +/* +* Copyright (C) 2014 Broadcom Corporation +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/delay.h> + +#define CFG_OFFSET 0x00 +#define CFG_RESET_SHIFT 31 +#define CFG_EN_SHIFT 30 +#define CFG_M_RETRY_CNT_SHIFT 16 +#define CFG_M_RETRY_CNT_MASK 0x0f + +#define TIM_CFG_OFFSET 0x04 +#define TIM_CFG_MODE_400_SHIFT 31 + +#define M_FIFO_CTRL_OFFSET 0x0c +#define M_FIFO_RX_FLUSH_SHIFT 31 +#define M_FIFO_TX_FLUSH_SHIFT 30 +#define M_FIFO_RX_CNT_SHIFT 16 +#define M_FIFO_RX_CNT_MASK 0x7f +#define M_FIFO_RX_THLD_SHIFT 8 +#define M_FIFO_RX_THLD_MASK 0x3f + +#define M_CMD_OFFSET 0x30 +#define M_CMD_START_BUSY_SHIFT 31 +#define M_CMD_STATUS_SHIFT 25 +#define M_CMD_STATUS_MASK 0x07 +#define M_CMD_STATUS_SUCCESS 0x0 +#define M_CMD_STATUS_LOST_ARB 0x1 +#define M_CMD_STATUS_NACK_ADDR 0x2 +#define M_CMD_STATUS_NACK_DATA 0x3 +#define M_CMD_STATUS_TIMEOUT 0x4 +#define M_CMD_PROTOCOL_SHIFT 9 +#define M_CMD_PROTOCOL_MASK 0xf +#define M_CMD_PROTOCOL_BLK_WR 0x7 +#define M_CMD_PROTOCOL_BLK_RD 0x8 +#define M_CMD_PEC_SHIFT 8 +#define M_CMD_RD_CNT_SHIFT 0 +#define M_CMD_RD_CNT_MASK 0xff + +#define IE_OFFSET 0x38 +#define IE_M_RX_FIFO_FULL_SHIFT 31 +#define IE_M_RX_THLD_SHIFT 30 +#define IE_M_START_BUSY_SHIFT 28 + +#define IS_OFFSET 0x3c +#define IS_M_RX_FIFO_FULL_SHIFT 31 +#define IS_M_RX_THLD_SHIFT 30 +#define IS_M_START_BUSY_SHIFT 28 + +#define M_TX_OFFSET 0x40 +#define M_TX_WR_STATUS_SHIFT 31 +#define M_TX_DATA_SHIFT 0 +#define M_TX_DATA_MASK 0xff + +#define M_RX_OFFSET 0x44 +#define M_RX_STATUS_SHIFT 30 +#define M_RX_STATUS_MASK 0x03 +#define M_RX_PEC_ERR_SHIFT 29 +#define M_RX_DATA_SHIFT 0 +#define M_RX_DATA_MASK 0xff + +#define I2C_TIMEOUT_MESC 100 +#define M_TX_RX_FIFO_SIZE 64 + +enum bus_speed_index { +I2C_SPD_100K =0 , +I2C_SPD_400K , +}; + +struct bcm_iproc_i2c_dev { +struct device *device; +int irq; + +void __iomem *base; + +struct i2c_adapter adapter; + +struct completion done; +int xfer_is_done; +}; + +/* +* Can be expanded in the future if more interrupt status bits are utilized +*/ +#define ISR_MASK (1 << IS_M_START_BUSY_SHIFT) + +static irqreturn_t bcm_iproc_i2c_isr (int irq,void *data) +{ +struct bcm_iproc_i2c_dev *iproc_i2c = data; +u32 status =readl (iproc_i2c->base +IS_OFFSET ); + + status &=ISR_MASK ; + +if (!status) +return IRQ_NONE ; + +writel (status, iproc_i2c->base +IS_OFFSET ); + iproc_i2c->xfer_is_done =1 ; +complete_all (&iproc_i2c->done); + +return IRQ_HANDLED ; +} + +static bool bcm_iproc_i2c_bus_busy (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +if (readl (iproc_i2c->base +M_CMD_OFFSET ) & + (1 <<M_CMD_START_BUSY_SHIFT )) +return true; +else +return false;
drivers/i2c/busses/i2c-bcm-iproc.c line 137
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+} + +static int bcm_iproc_i2c_format_addr (struct bcm_iproc_i2c_dev *iproc_i2c, +struct i2c_msg *msg,u8 *addr) +{ + +if (msg->flags &I2C_M_TEN ) { +dev_err (iproc_i2c->device,"no support for 10-bit address\n" ); +return -EINVAL ; + }
This looks harmless, but might be redundant since you aren't advertising I2C_FUNC_10BIT_ADDR anyway.
Quoted 47 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +47
-0+ + *addr = msg->addr <<1 ; + +if (msg->flags &I2C_M_RD ) + *addr |=1 ; + +return 0 ; +} + +static int bcm_iproc_i2c_check_status (struct bcm_iproc_i2c_dev *iproc_i2c, +struct i2c_msg *msg) +{ +u32 val; + + val =readl (iproc_i2c->base +M_CMD_OFFSET ); + val = (val >>M_CMD_STATUS_SHIFT ) &M_CMD_STATUS_MASK ; + +switch (val) { +case M_CMD_STATUS_SUCCESS : +return 0 ; + +case M_CMD_STATUS_LOST_ARB : +dev_dbg (iproc_i2c->device,"lost bus arbitration\n" ); +return -EAGAIN ; + +case M_CMD_STATUS_NACK_ADDR : +dev_dbg (iproc_i2c->device,"NAK addr:0x%02x\n" , msg->addr); +return -ENXIO ; + +case M_CMD_STATUS_NACK_DATA : +dev_dbg (iproc_i2c->device,"NAK data\n" ); +return -ENXIO ; + +case M_CMD_STATUS_TIMEOUT : +dev_dbg (iproc_i2c->device,"bus timeout\n" ); +return -ETIMEDOUT ; + +default : +dev_dbg (iproc_i2c->device,"unknown error code=%d\n" , val); +return -EIO ; + } +} + +static int bcm_iproc_i2c_xfer_single_msg (struct bcm_iproc_i2c_dev *iproc_i2c, +struct i2c_msg *msg) +{ +int ret, i;
drivers/i2c/busses/i2c-bcm-iproc.c line 194
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+u8 addr; +u32 val; +unsigned long time_left =msecs_to_jiffies (I2C_TIMEOUT_MESC ); + +if (msg->len >M_TX_RX_FIFO_SIZE -1 ) { +dev_err (iproc_i2c->device, +"only support data length up to %u bytes\n" , +M_TX_RX_FIFO_SIZE -1 ); +return -EINVAL ; + }
If the FIFO is 64 bytes, are we limited to 63 bytes of data because the slave address consumes 1 byte of FIFO space? If so, it might be helpful to add a comment to that effect.
Quoted 14 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +14
-0+ +if (bcm_iproc_i2c_bus_busy (iproc_i2c)) { +dev_warn (iproc_i2c->device,"bus is busy\n" ); +return -EBUSY ; + } + + ret =bcm_iproc_i2c_format_addr (iproc_i2c, msg, &addr); +if (ret) +return ret; + +/* load slave address into the TX FIFO */ +writel (addr, iproc_i2c->base +M_TX_OFFSET ); + +/* for a write transaction, load data into the TX FIFO */
drivers/i2c/busses/i2c-bcm-iproc.c line 218
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+if (!(msg->flags &I2C_M_RD )) { +for (i =0 ; i < msg->len; i++) { + val = msg->buf[i]; + +/* mark the last byte */ +if (i == msg->len -1 ) + val |=1 <<M_TX_WR_STATUS_SHIFT ; + +writel (val, iproc_i2c->base +M_TX_OFFSET ); + }
If msg->len == 1 and msg->buf[0] == 0x00, we will writel(0x80000000, iproc_i2c->base + M_TX_OFFSET);
drivers/i2c/busses/i2c-bcm-iproc.c line 222
Quoted 4 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +4
-0+ +if (msg->len ==0 ) +writel (1 <<M_TX_WR_STATUS_SHIFT , + iproc_i2c->base +M_TX_OFFSET );
...so if msg->len == 0, does that mean this sends a dummy 0x00 data byte out on the wire?
If that's a hardware limitation (M_TX_WR_STATUS_SHIFT prohibited on the address byte), it's probably worth leaving a note in the code.
Quoted 63 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +63
-0+ } + +/* mark as incomplete before starting the transaction */ +reinit_completion (&iproc_i2c->done); + iproc_i2c->xfer_is_done =0 ; + +/* +* Enable the "start busy" interrupt, which will be triggered after the +* transaction is done, i.e., the internal start_busy bit, transitions +* from 1 to 0. +*/ +writel (1 <<IE_M_START_BUSY_SHIFT , iproc_i2c->base +IE_OFFSET ); + +/* +* Now we can activate the transfer. For a read operation, specify the +* number of bytes to read +*/ + val =1 <<M_CMD_START_BUSY_SHIFT ; +if (msg->flags &I2C_M_RD ) { + val |= (M_CMD_PROTOCOL_BLK_RD <<M_CMD_PROTOCOL_SHIFT ) | + (msg->len <<M_CMD_RD_CNT_SHIFT ); + }else { + val |= (M_CMD_PROTOCOL_BLK_WR <<M_CMD_PROTOCOL_SHIFT ); + } +writel (val, iproc_i2c->base +M_CMD_OFFSET ); + + time_left =wait_for_completion_timeout (&iproc_i2c->done, time_left); + +/* disable all interrupts */ +writel (0 , iproc_i2c->base +IE_OFFSET ); +/* read it back to flush the write */ +readl (iproc_i2c->base +IE_OFFSET ); + +/* make sure the interrupt handler isn't running */ +synchronize_irq (iproc_i2c->irq); + +if (!time_left && !iproc_i2c->xfer_is_done) { +dev_err (iproc_i2c->device,"transaction timed out\n" ); + +/* flush FIFOs */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | + (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, iproc_i2c->base +M_FIFO_CTRL_OFFSET ); +return -ETIMEDOUT ; + } + + ret =bcm_iproc_i2c_check_status (iproc_i2c, msg); +if (ret) { +/* flush both TX/RX FIFOs */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | + (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, iproc_i2c->base +M_FIFO_CTRL_OFFSET ); +return ret; + } + +/* +* For a read operation, we now need to load the data from FIFO +* into the memory buffer +*/ +if (msg->flags &I2C_M_RD ) { +for (i =0 ; i < msg->len; i++) { + msg->buf[i] = (readl (iproc_i2c->base +M_RX_OFFSET ) >> +M_RX_DATA_SHIFT ) &M_RX_DATA_MASK ;
drivers/i2c/busses/i2c-bcm-iproc.c line 295
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ } + } + +dev_dbg (iproc_i2c->device,"xfer %c, addr=0x%02x, len=%d\n" , + (msg->flags &I2C_M_RD ) ?'R' :'W' , msg->addr, + msg->len); +dev_dbg (iproc_i2c->device,"**** data start ****\n" ); +for (i =0 ; i < msg->len; i++) +dev_dbg (iproc_i2c->device,"0x%02x " , msg->buf[i]); +dev_dbg (iproc_i2c->device,"**** data end ****\n" );
It might be simpler to just do:
print_hex_dump_bytes("iproc_i2c:", DUMP_PREFIX_NONE, msg->buf, msg->len);although you'd lose the ability to see the I2C device name.
Quoted 53 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +53
-0+ +return 0 ; +} + +static int bcm_iproc_i2c_xfer (struct i2c_adapter *adapter, +struct i2c_msg msgs[],int num) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =i2c_get_adapdata (adapter); +int ret, i; + +/* go through all messages */ +for (i =0 ; i < num; i++) { + ret =bcm_iproc_i2c_xfer_single_msg (iproc_i2c, &msgs[i]); +if (ret) { +dev_err (iproc_i2c->device,"xfer failed\n" ); +return ret; + } + } + +return num; +} + +static uint32_t bcm_iproc_i2c_functionality (struct i2c_adapter *adap) +{ +return I2C_FUNC_I2C |I2C_FUNC_SMBUS_EMUL ; +} + +static const struct i2c_algorithm bcm_iproc_algo = { + .master_xfer = bcm_iproc_i2c_xfer, + .functionality = bcm_iproc_i2c_functionality, +}; + +static int bcm_iproc_i2c_cfg_speed (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +unsigned int bus_speed, speed_bit; +u32 val; +int ret =of_property_read_u32 (iproc_i2c->device->of_node, +"clock-frequency" , &bus_speed); +if (ret <0 ) { +dev_info (iproc_i2c->device, +"unable to interpret clock-frequency DT property\n" ); + bus_speed =100000 ; + } + +if (bus_speed <100000 ) { +dev_err (iproc_i2c->device,"%d Hz bus speed not supported\n" , + bus_speed); +dev_err (iproc_i2c->device, +"valid speeds are 100khz and 400khz\n" ); +return -EINVAL ; + }else if (bus_speed <400000 ) { + speed_bit =0 ; + }else {
drivers/i2c/busses/i2c-bcm-iproc.c line 358
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+/* bus_speed >= 400000 */ + speed_bit =1 ; + } + + val =readl (iproc_i2c->base +TIM_CFG_OFFSET ); + val &= ~(1 <<TIM_CFG_MODE_400_SHIFT ); + val |= speed_bit <<TIM_CFG_MODE_400_SHIFT ; +writel (val, iproc_i2c->base +TIM_CFG_OFFSET ); + +dev_info (iproc_i2c->device,"bus set to %u Hz\n" , bus_speed);
The message would be more accurate if it reported 100 kHz or 400 kHz, since the driver isn't able to support arbitrary speeds. Somebody could be surprised if they ask for 200 kHz but the transactions run at 100 kHz.
Quoted 76 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +76
-0+ +return 0 ; +} + +static int bcm_iproc_i2c_init (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +u32 val; + +/* put controller in reset */ + val =readl (iproc_i2c->base +CFG_OFFSET ); + val |=1 <<CFG_RESET_SHIFT ; + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, iproc_i2c->base +CFG_OFFSET ); + +/* wait 100 usec per spec */ +udelay (100 ); + +/* bring controller out of reset */ + val &= ~(1 <<CFG_RESET_SHIFT ); +writel (val, iproc_i2c->base +CFG_OFFSET ); + +/* flush TX/RX FIFOs and set RX FIFO threshold to zero */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, iproc_i2c->base +M_FIFO_CTRL_OFFSET ); + +/* disable all interrupts */ +writel (0 , iproc_i2c->base +IE_OFFSET ); + +/* clear all pending interrupts */ +writel (0xffffffff , iproc_i2c->base +IS_OFFSET ); + +return 0 ; +} + +static void bcm_iproc_i2c_enable (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +u32 val; + + val =readl (iproc_i2c->base +CFG_OFFSET ); + val |=1 <<CFG_EN_SHIFT ; +writel (val, iproc_i2c->base +CFG_OFFSET ); +} + +static void bcm_iproc_i2c_disable (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +u32 val; + + val =readl (iproc_i2c->base +CFG_OFFSET ); + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, iproc_i2c->base +CFG_OFFSET ); +} + +static int bcm_iproc_i2c_probe (struct platform_device *pdev) +{ +int irq, ret =0 ; +struct bcm_iproc_i2c_dev *iproc_i2c; +struct i2c_adapter *adap; +struct resource *res; + + iproc_i2c =devm_kzalloc (&pdev->dev,sizeof (*iproc_i2c), +GFP_KERNEL ); +if (!iproc_i2c) +return -ENOMEM ; + +platform_set_drvdata (pdev, iproc_i2c); + iproc_i2c->device = &pdev->dev; +init_completion (&iproc_i2c->done); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + iproc_i2c->base =devm_ioremap_resource (iproc_i2c->device, res); +if (IS_ERR (iproc_i2c->base)) +return PTR_ERR (iproc_i2c->base); + + ret =bcm_iproc_i2c_init (iproc_i2c); +if (ret) +return ret;
drivers/i2c/busses/i2c-bcm-iproc.c line 444
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ + ret =bcm_iproc_i2c_cfg_speed (iproc_i2c); +if (ret) +return ret; + + irq =platform_get_irq (pdev,0 ); +if (irq <=0 ) { +dev_err (iproc_i2c->device,"no irq resource\n" ); +return irq; + }
AFAICT platform_get_irq() can return IRQ 0 on success. Unlike irq_of_parse_and_map().
Other than that it looks fine to me, so for all three patches in the series:
Quoted 61 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +61
-0+ iproc_i2c->irq = irq; + + ret =devm_request_irq (iproc_i2c->device, irq, bcm_iproc_i2c_isr,0 , + pdev->name, iproc_i2c); +if (ret <0 ) { +dev_err (iproc_i2c->device,"unable to request irq %i\n" , irq); +return ret; + } + +bcm_iproc_i2c_enable (iproc_i2c); + + adap = &iproc_i2c->adapter; +i2c_set_adapdata (adap, iproc_i2c); +strlcpy (adap->name,"Broadcom iProc I2C adapter" ,sizeof (adap->name)); + adap->algo = &bcm_iproc_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + + ret =i2c_add_adapter (adap); +if (ret) { +dev_err (iproc_i2c->device,"failed to add adapter\n" ); +return ret; + } + +return 0 ; +} + +static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =platform_get_drvdata (pdev); + +/* make sure there's no pending interrupt when we remove the adapter */ +writel (0 , iproc_i2c->base +IE_OFFSET ); +readl (iproc_i2c->base +IE_OFFSET ); +synchronize_irq (iproc_i2c->irq); + +i2c_del_adapter (&iproc_i2c->adapter); +bcm_iproc_i2c_disable (iproc_i2c); + +return 0 ; +} + +static const struct of_device_id bcm_iproc_i2c_of_match[] = { + { .compatible ="brcm,iproc-i2c" }, + {/* sentinel */ } +}; +MODULE_DEVICE_TABLE (of, bcm_iproc_i2c_of_match); + +static struct platform_driver bcm_iproc_i2c_driver = { + .driver = { + .name ="bcm-iproc-i2c" , + .of_match_table = bcm_iproc_i2c_of_match, + }, + .probe = bcm_iproc_i2c_probe, + .remove = bcm_iproc_i2c_remove, +}; +module_platform_driver (bcm_iproc_i2c_driver); + +MODULE_AUTHOR ("Ray Jui <rjui <at> broadcom.com>" ); +MODULE_DESCRIPTION ("Broadcom iProc I2C Driver" ); +MODULE_LICENSE ("GPL v2" );
Re: [v7,2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 10 lines · Kevin Cernekee
drivers/i2c/busses/i2c-bcm-iproc.c line 295
Quoted 8 lines · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+ +dev_dbg (iproc_i2c->device,"xfer %c, addr=0x%02x, len=%d\n" , + (msg->flags &I2C_M_RD ) ?'R' :'W' , msg->addr, + msg->len); +dev_dbg (iproc_i2c->device,"**** data start ****\n" ); +for (i =0 ; i < msg->len; i++) +dev_dbg (iproc_i2c->device,"0x%02x " , msg->buf[i]); +dev_dbg (iproc_i2c->device,"**** data end ****\n" );
Quoted 5 lines
It might be simpler to just do:
print_hex_dump_bytes("iproc_i2c:", DUMP_PREFIX_NONE, msg->buf, msg->len);although you'd lose the ability to see the I2C device name.
We can also do:
dev_dbg(iproc_i2c->device, "*** data: %*ph\n", msg->len, msg->buf);
if we are OK with limiting output to 64 bytes.
Thanks,
Dmitry
Re: [v7,2/3] i2c: iproc: Add Broadcom iProc I2C Driver
Quoted 15 lines · Dmitry Torokhov
Quoted 14 lines · Kevin Cernekee
drivers/i2c/busses/i2c-bcm-iproc.c line 295
Quoted 8 lines · Ray Jui
drivers/i2c/busses/i2c-bcm-iproc.c new file +8
-0+ +dev_dbg (iproc_i2c->device,"xfer %c, addr=0x%02x, len=%d\n" , + (msg->flags &I2C_M_RD ) ?'R' :'W' , msg->addr, + msg->len); +dev_dbg (iproc_i2c->device,"**** data start ****\n" ); +for (i =0 ; i < msg->len; i++) +dev_dbg (iproc_i2c->device,"0x%02x " , msg->buf[i]); +dev_dbg (iproc_i2c->device,"**** data end ****\n" );It might be simpler to just do:
print_hex_dump_bytes("iproc_i2c:", DUMP_PREFIX_NONE, msg->buf, msg->len);
Quoted 7 lines
Quoted 1 line
although you'd lose the ability to see the I2C device name.
We can also do:
dev_dbg(iproc_i2c->device, "*** data: %*ph\n", msg->len, msg->buf);if we are OK with limiting output to 64 bytes.
msg->len is capped at 63 due to hardware limits, so that should work.
Ray Jui
maintainerRe: [v7,2/3] i2c: iproc: Add Broadcom iProc I2C Driver
In reply to Kevin CernekeeQuoted 187 lines · Kevin Cernekee
Quoted 186 lines · Ray Jui
Add initial support to the Broadcom iProc I2C controller found in the iProc family of SoCs.
The iProc I2C controller has separate internal TX and RX FIFOs, each has a size of 64 bytes. The iProc I2C controller supports two bus speeds including standard mode (100kHz) and fast mode (400kHz)
Signed-off-by Ray Jui <rjui <at> broadcom.com>Reviewed-by Scott Branden <sbranden <at> broadcom.com>--- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm-iproc.c | 505 ++++++++++++++++++++++++++++++++++++ 3 files changed, 516 insertions(+) create mode 100644 drivers/i2c/busses/i2c-bcm-iproc.cdrivers/i2c/busses/Kconfig +10
-0<at> <at> -372,6 +372,16 <at> <at> config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC || COMPILE_TEST + default ARCH_BCM_IPROC + help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILEdrivers/i2c/busses/Makefile +1
-0<at> <at> -33,6 +33,7 <at> <at> obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.odrivers/i2c/busses/i2c-bcm-iproc.c new file +131
-0<at> <at> -0,0 +1,505 <at> <at> +/* +* Copyright (C) 2014 Broadcom Corporation +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/delay.h> + +#define CFG_OFFSET 0x00 +#define CFG_RESET_SHIFT 31 +#define CFG_EN_SHIFT 30 +#define CFG_M_RETRY_CNT_SHIFT 16 +#define CFG_M_RETRY_CNT_MASK 0x0f + +#define TIM_CFG_OFFSET 0x04 +#define TIM_CFG_MODE_400_SHIFT 31 + +#define M_FIFO_CTRL_OFFSET 0x0c +#define M_FIFO_RX_FLUSH_SHIFT 31 +#define M_FIFO_TX_FLUSH_SHIFT 30 +#define M_FIFO_RX_CNT_SHIFT 16 +#define M_FIFO_RX_CNT_MASK 0x7f +#define M_FIFO_RX_THLD_SHIFT 8 +#define M_FIFO_RX_THLD_MASK 0x3f + +#define M_CMD_OFFSET 0x30 +#define M_CMD_START_BUSY_SHIFT 31 +#define M_CMD_STATUS_SHIFT 25 +#define M_CMD_STATUS_MASK 0x07 +#define M_CMD_STATUS_SUCCESS 0x0 +#define M_CMD_STATUS_LOST_ARB 0x1 +#define M_CMD_STATUS_NACK_ADDR 0x2 +#define M_CMD_STATUS_NACK_DATA 0x3 +#define M_CMD_STATUS_TIMEOUT 0x4 +#define M_CMD_PROTOCOL_SHIFT 9 +#define M_CMD_PROTOCOL_MASK 0xf +#define M_CMD_PROTOCOL_BLK_WR 0x7 +#define M_CMD_PROTOCOL_BLK_RD 0x8 +#define M_CMD_PEC_SHIFT 8 +#define M_CMD_RD_CNT_SHIFT 0 +#define M_CMD_RD_CNT_MASK 0xff + +#define IE_OFFSET 0x38 +#define IE_M_RX_FIFO_FULL_SHIFT 31 +#define IE_M_RX_THLD_SHIFT 30 +#define IE_M_START_BUSY_SHIFT 28 + +#define IS_OFFSET 0x3c +#define IS_M_RX_FIFO_FULL_SHIFT 31 +#define IS_M_RX_THLD_SHIFT 30 +#define IS_M_START_BUSY_SHIFT 28 + +#define M_TX_OFFSET 0x40 +#define M_TX_WR_STATUS_SHIFT 31 +#define M_TX_DATA_SHIFT 0 +#define M_TX_DATA_MASK 0xff + +#define M_RX_OFFSET 0x44 +#define M_RX_STATUS_SHIFT 30 +#define M_RX_STATUS_MASK 0x03 +#define M_RX_PEC_ERR_SHIFT 29 +#define M_RX_DATA_SHIFT 0 +#define M_RX_DATA_MASK 0xff + +#define I2C_TIMEOUT_MESC 100 +#define M_TX_RX_FIFO_SIZE 64 + +enum bus_speed_index { +I2C_SPD_100K =0 , +I2C_SPD_400K , +}; + +struct bcm_iproc_i2c_dev { +struct device *device; +int irq; + +void __iomem *base; + +struct i2c_adapter adapter; + +struct completion done; +int xfer_is_done; +}; + +/* +* Can be expanded in the future if more interrupt status bits are utilized +*/ +#define ISR_MASK (1 << IS_M_START_BUSY_SHIFT) + +static irqreturn_t bcm_iproc_i2c_isr (int irq,void *data) +{ +struct bcm_iproc_i2c_dev *iproc_i2c = data; +u32 status =readl (iproc_i2c->base +IS_OFFSET ); + + status &=ISR_MASK ; + +if (!status) +return IRQ_NONE ; + +writel (status, iproc_i2c->base +IS_OFFSET ); + iproc_i2c->xfer_is_done =1 ; +complete_all (&iproc_i2c->done); + +return IRQ_HANDLED ; +} + +static bool bcm_iproc_i2c_bus_busy (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +if (readl (iproc_i2c->base +M_CMD_OFFSET ) & + (1 <<M_CMD_START_BUSY_SHIFT )) +return true; +else +return false; +} + +static int bcm_iproc_i2c_format_addr (struct bcm_iproc_i2c_dev *iproc_i2c, +struct i2c_msg *msg,u8 *addr)
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 137
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+{ + +if (msg->flags &I2C_M_TEN ) { +dev_err (iproc_i2c->device,"no support for 10-bit address\n" ); +return -EINVAL ; + }This looks harmless, but might be redundant since you aren't advertising
I2C_FUNC_10BIT_ADDRanyway.
Okay I'll remove that.
Quoted 51 lines
Quoted 51 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +51
-0+ + *addr = msg->addr <<1 ; + +if (msg->flags &I2C_M_RD ) + *addr |=1 ; + +return 0 ; +} + +static int bcm_iproc_i2c_check_status (struct bcm_iproc_i2c_dev *iproc_i2c, +struct i2c_msg *msg) +{ +u32 val; + + val =readl (iproc_i2c->base +M_CMD_OFFSET ); + val = (val >>M_CMD_STATUS_SHIFT ) &M_CMD_STATUS_MASK ; + +switch (val) { +case M_CMD_STATUS_SUCCESS : +return 0 ; + +case M_CMD_STATUS_LOST_ARB : +dev_dbg (iproc_i2c->device,"lost bus arbitration\n" ); +return -EAGAIN ; + +case M_CMD_STATUS_NACK_ADDR : +dev_dbg (iproc_i2c->device,"NAK addr:0x%02x\n" , msg->addr); +return -ENXIO ; + +case M_CMD_STATUS_NACK_DATA : +dev_dbg (iproc_i2c->device,"NAK data\n" ); +return -ENXIO ; + +case M_CMD_STATUS_TIMEOUT : +dev_dbg (iproc_i2c->device,"bus timeout\n" ); +return -ETIMEDOUT ; + +default : +dev_dbg (iproc_i2c->device,"unknown error code=%d\n" , val); +return -EIO ; + } +} + +static int bcm_iproc_i2c_xfer_single_msg (struct bcm_iproc_i2c_dev *iproc_i2c, +struct i2c_msg *msg) +{ +int ret, i; +u8 addr; +u32 val; +unsigned long time_left =msecs_to_jiffies (I2C_TIMEOUT_MESC ); +
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 194
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+if (msg->len >M_TX_RX_FIFO_SIZE -1 ) { +dev_err (iproc_i2c->device, +"only support data length up to %u bytes\n" , +M_TX_RX_FIFO_SIZE -1 ); +return -EINVAL ; + }If the FIFO is 64 bytes, are we limited to 63 bytes of data because the slave address consumes 1 byte of FIFO space? If so, it might be helpful to add a comment to that effect.
Yeah I'll add a comment to explain this.
Quoted 27 lines
Quoted 14 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +14
-0+ +if (bcm_iproc_i2c_bus_busy (iproc_i2c)) { +dev_warn (iproc_i2c->device,"bus is busy\n" ); +return -EBUSY ; + } + + ret =bcm_iproc_i2c_format_addr (iproc_i2c, msg, &addr); +if (ret) +return ret; + +/* load slave address into the TX FIFO */ +writel (addr, iproc_i2c->base +M_TX_OFFSET ); + +/* for a write transaction, load data into the TX FIFO */ drivers/i2c/busses/i2c-bcm-iproc.c line 218
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+if (!(msg->flags &I2C_M_RD )) { +for (i =0 ; i < msg->len; i++) { + val = msg->buf[i]; + +/* mark the last byte */ +if (i == msg->len -1 ) + val |=1 <<M_TX_WR_STATUS_SHIFT ; + +writel (val, iproc_i2c->base +M_TX_OFFSET ); + }If
msg->len== 1 and msg->buf[0] ==0x00, we willwritel(0x80000000, iproc_i2c->base + M_TX_OFFSET);
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 222
Quoted 4 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +4
-0+ +if (msg->len ==0 ) +writel (1 <<M_TX_WR_STATUS_SHIFT , + iproc_i2c->base +M_TX_OFFSET );...so if
msg->len== 0, does that mean this sends a dummy0x00data byte out on the wire?If that's a hardware limitation (
M_TX_WR_STATUS_SHIFTprohibited on the address byte), it's probably worth leaving a note in the code.
In fact, I made a mistake here. The if statement should be completely removed. Thanks for catching this!
Quoted 76 lines
Quoted 63 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +63
-0+ } + +/* mark as incomplete before starting the transaction */ +reinit_completion (&iproc_i2c->done); + iproc_i2c->xfer_is_done =0 ; + +/* +* Enable the "start busy" interrupt, which will be triggered after the +* transaction is done, i.e., the internal start_busy bit, transitions +* from 1 to 0. +*/ +writel (1 <<IE_M_START_BUSY_SHIFT , iproc_i2c->base +IE_OFFSET ); + +/* +* Now we can activate the transfer. For a read operation, specify the +* number of bytes to read +*/ + val =1 <<M_CMD_START_BUSY_SHIFT ; +if (msg->flags &I2C_M_RD ) { + val |= (M_CMD_PROTOCOL_BLK_RD <<M_CMD_PROTOCOL_SHIFT ) | + (msg->len <<M_CMD_RD_CNT_SHIFT ); + }else { + val |= (M_CMD_PROTOCOL_BLK_WR <<M_CMD_PROTOCOL_SHIFT ); + } +writel (val, iproc_i2c->base +M_CMD_OFFSET ); + + time_left =wait_for_completion_timeout (&iproc_i2c->done, time_left); + +/* disable all interrupts */ +writel (0 , iproc_i2c->base +IE_OFFSET ); +/* read it back to flush the write */ +readl (iproc_i2c->base +IE_OFFSET ); + +/* make sure the interrupt handler isn't running */ +synchronize_irq (iproc_i2c->irq); + +if (!time_left && !iproc_i2c->xfer_is_done) { +dev_err (iproc_i2c->device,"transaction timed out\n" ); + +/* flush FIFOs */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | + (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, iproc_i2c->base +M_FIFO_CTRL_OFFSET ); +return -ETIMEDOUT ; + } + + ret =bcm_iproc_i2c_check_status (iproc_i2c, msg); +if (ret) { +/* flush both TX/RX FIFOs */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | + (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, iproc_i2c->base +M_FIFO_CTRL_OFFSET ); +return ret; + } + +/* +* For a read operation, we now need to load the data from FIFO +* into the memory buffer +*/ +if (msg->flags &I2C_M_RD ) { +for (i =0 ; i < msg->len; i++) { + msg->buf[i] = (readl (iproc_i2c->base +M_RX_OFFSET ) >> +M_RX_DATA_SHIFT ) &M_RX_DATA_MASK ;drivers/i2c/busses/i2c-bcm-iproc.c line 295
Quoted 10 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +10
-0+ } + } + +dev_dbg (iproc_i2c->device,"xfer %c, addr=0x%02x, len=%d\n" , + (msg->flags &I2C_M_RD ) ?'R' :'W' , msg->addr, + msg->len); +dev_dbg (iproc_i2c->device,"**** data start ****\n" ); +for (i =0 ; i < msg->len; i++) +dev_dbg (iproc_i2c->device,"0x%02x " , msg->buf[i]); +dev_dbg (iproc_i2c->device,"**** data end ****\n" );It might be simpler to just do:
Quoted 4 lines
print_hex_dump_bytes("iproc_i2c:", DUMP_PREFIX_NONE, msg->buf, msg->len);although you'd lose the ability to see the I2C device name.
Great! I'll change this to:dev_dbg(iproc_i2c->device, "*** data: %*ph\n", msg->len, msg->buf); per discussions between you and Dmitry.
Quoted 57 lines
Quoted 57 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +57
-0+ +return 0 ; +} + +static int bcm_iproc_i2c_xfer (struct i2c_adapter *adapter, +struct i2c_msg msgs[],int num) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =i2c_get_adapdata (adapter); +int ret, i; + +/* go through all messages */ +for (i =0 ; i < num; i++) { + ret =bcm_iproc_i2c_xfer_single_msg (iproc_i2c, &msgs[i]); +if (ret) { +dev_err (iproc_i2c->device,"xfer failed\n" ); +return ret; + } + } + +return num; +} + +static uint32_t bcm_iproc_i2c_functionality (struct i2c_adapter *adap) +{ +return I2C_FUNC_I2C |I2C_FUNC_SMBUS_EMUL ; +} + +static const struct i2c_algorithm bcm_iproc_algo = { + .master_xfer = bcm_iproc_i2c_xfer, + .functionality = bcm_iproc_i2c_functionality, +}; + +static int bcm_iproc_i2c_cfg_speed (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +unsigned int bus_speed, speed_bit; +u32 val; +int ret =of_property_read_u32 (iproc_i2c->device->of_node, +"clock-frequency" , &bus_speed); +if (ret <0 ) { +dev_info (iproc_i2c->device, +"unable to interpret clock-frequency DT property\n" ); + bus_speed =100000 ; + } + +if (bus_speed <100000 ) { +dev_err (iproc_i2c->device,"%d Hz bus speed not supported\n" , + bus_speed); +dev_err (iproc_i2c->device, +"valid speeds are 100khz and 400khz\n" ); +return -EINVAL ; + }else if (bus_speed <400000 ) { + speed_bit =0 ; + }else { +/* bus_speed >= 400000 */ + speed_bit =1 ; + } +
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 358
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+ val =readl (iproc_i2c->base +TIM_CFG_OFFSET ); + val &= ~(1 <<TIM_CFG_MODE_400_SHIFT ); + val |= speed_bit <<TIM_CFG_MODE_400_SHIFT ; +writel (val, iproc_i2c->base +TIM_CFG_OFFSET ); + +dev_info (iproc_i2c->device,"bus set to %u Hz\n" , bus_speed);The message would be more accurate if it reported 100 kHz or 400 kHz, since the driver isn't able to support arbitrary speeds. Somebody could be surprised if they ask for 200 kHz but the transactions run at 100 kHz.
Right. I'll update bus_speed to the real speed that it got set to in the above code.
Quoted 80 lines
Quoted 80 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +80
-0+ +return 0 ; +} + +static int bcm_iproc_i2c_init (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +u32 val; + +/* put controller in reset */ + val =readl (iproc_i2c->base +CFG_OFFSET ); + val |=1 <<CFG_RESET_SHIFT ; + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, iproc_i2c->base +CFG_OFFSET ); + +/* wait 100 usec per spec */ +udelay (100 ); + +/* bring controller out of reset */ + val &= ~(1 <<CFG_RESET_SHIFT ); +writel (val, iproc_i2c->base +CFG_OFFSET ); + +/* flush TX/RX FIFOs and set RX FIFO threshold to zero */ + val = (1 <<M_FIFO_RX_FLUSH_SHIFT ) | (1 <<M_FIFO_TX_FLUSH_SHIFT ); +writel (val, iproc_i2c->base +M_FIFO_CTRL_OFFSET ); + +/* disable all interrupts */ +writel (0 , iproc_i2c->base +IE_OFFSET ); + +/* clear all pending interrupts */ +writel (0xffffffff , iproc_i2c->base +IS_OFFSET ); + +return 0 ; +} + +static void bcm_iproc_i2c_enable (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +u32 val; + + val =readl (iproc_i2c->base +CFG_OFFSET ); + val |=1 <<CFG_EN_SHIFT ; +writel (val, iproc_i2c->base +CFG_OFFSET ); +} + +static void bcm_iproc_i2c_disable (struct bcm_iproc_i2c_dev *iproc_i2c) +{ +u32 val; + + val =readl (iproc_i2c->base +CFG_OFFSET ); + val &= ~(1 <<CFG_EN_SHIFT ); +writel (val, iproc_i2c->base +CFG_OFFSET ); +} + +static int bcm_iproc_i2c_probe (struct platform_device *pdev) +{ +int irq, ret =0 ; +struct bcm_iproc_i2c_dev *iproc_i2c; +struct i2c_adapter *adap; +struct resource *res; + + iproc_i2c =devm_kzalloc (&pdev->dev,sizeof (*iproc_i2c), +GFP_KERNEL ); +if (!iproc_i2c) +return -ENOMEM ; + +platform_set_drvdata (pdev, iproc_i2c); + iproc_i2c->device = &pdev->dev; +init_completion (&iproc_i2c->done); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + iproc_i2c->base =devm_ioremap_resource (iproc_i2c->device, res); +if (IS_ERR (iproc_i2c->base)) +return PTR_ERR (iproc_i2c->base); + + ret =bcm_iproc_i2c_init (iproc_i2c); +if (ret) +return ret; + + ret =bcm_iproc_i2c_cfg_speed (iproc_i2c); +if (ret) +return ret;
Quoted 9 lines
drivers/i2c/busses/i2c-bcm-iproc.c line 444
Quoted 6 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +6
-0+ + irq =platform_get_irq (pdev,0 ); +if (irq <=0 ) { +dev_err (iproc_i2c->device,"no irq resource\n" ); +return irq; + }AFAICT
platform_get_irq()can return IRQ 0 on success. Unlikeirq_of_parse_and_map().
In fact, irq_create_of_mapping (platform_get_irq -> of_irq_get -> irq_create_of_mapping) can return 0 when failed.
Quoted 5 lines
Other than that it looks fine to me, so for all three patches in the series:
Reviewed-by Kevin Cernekee <[email protected]>
Thank you so much for the review!
Quoted 61 lines
Quoted 61 lines
drivers/i2c/busses/i2c-bcm-iproc.c new file +61
-0+ iproc_i2c->irq = irq; + + ret =devm_request_irq (iproc_i2c->device, irq, bcm_iproc_i2c_isr,0 , + pdev->name, iproc_i2c); +if (ret <0 ) { +dev_err (iproc_i2c->device,"unable to request irq %i\n" , irq); +return ret; + } + +bcm_iproc_i2c_enable (iproc_i2c); + + adap = &iproc_i2c->adapter; +i2c_set_adapdata (adap, iproc_i2c); +strlcpy (adap->name,"Broadcom iProc I2C adapter" ,sizeof (adap->name)); + adap->algo = &bcm_iproc_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + + ret =i2c_add_adapter (adap); +if (ret) { +dev_err (iproc_i2c->device,"failed to add adapter\n" ); +return ret; + } + +return 0 ; +} + +static int bcm_iproc_i2c_remove (struct platform_device *pdev) +{ +struct bcm_iproc_i2c_dev *iproc_i2c =platform_get_drvdata (pdev); + +/* make sure there's no pending interrupt when we remove the adapter */ +writel (0 , iproc_i2c->base +IE_OFFSET ); +readl (iproc_i2c->base +IE_OFFSET ); +synchronize_irq (iproc_i2c->irq); + +i2c_del_adapter (&iproc_i2c->adapter); +bcm_iproc_i2c_disable (iproc_i2c); + +return 0 ; +} + +static const struct of_device_id bcm_iproc_i2c_of_match[] = { + { .compatible ="brcm,iproc-i2c" }, + {/* sentinel */ } +}; +MODULE_DEVICE_TABLE (of, bcm_iproc_i2c_of_match); + +static struct platform_driver bcm_iproc_i2c_driver = { + .driver = { + .name ="bcm-iproc-i2c" , + .of_match_table = bcm_iproc_i2c_of_match, + }, + .probe = bcm_iproc_i2c_probe, + .remove = bcm_iproc_i2c_remove, +}; +module_platform_driver (bcm_iproc_i2c_driver); + +MODULE_AUTHOR ("Ray Jui <rjui <at> broadcom.com>" ); +MODULE_DESCRIPTION ("Broadcom iProc I2C Driver" ); +MODULE_LICENSE ("GPL v2" );
Ray Jui
maintainerPATCH v7 3/3 ARM: dts: add I2C device nodes for Broadcom Cygnus
In reply to Ray JuiAdd I2C device nodes and its properties in bcm-cygnus.dtsi but keep them disabled there. Individual I2C devices can be enabled in board specific dts file when I2C slave devices are enabled in the future
--- arch/arm/boot/dts/bcm-cygnus.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
arch/arm/boot/dts/bcm-cygnus.dtsi +20 -0
@@ -70,6 +70,26 @@ }; }; + i2c0: i2c@18008000 { + compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c@1800b000 { + compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c"; + reg = <0x1800b000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>; + clock-frequency = <100000>; + status = "disabled"; + }; + uart0: serial@18020000 { compatible = "snps,dw-apb-uart"; reg = <0x18020000 0x100>;
Signature · 1 line
1.7.9.5
Ray Jui
maintainerv3 cover Add pinctrl support to Broadcom Cygnus SoC
In reply to a message not in the archiveThis patchset contains the initial pinctrl (IOMUX) support for the Broadcom Cygnus SoC. The Cygnus IOMUX controller supports group based mux configuration and allows certain pins to be muxed to GPIO function individually
Changes from v2:
- Consolidate all Broadcom pinctrl drivers into drivers/pinctrl/bcm/*
- Change the Cygnus IOMUX driver to use standard Linux pinctrl subnode
properties such as "function" and "groups" for pinmux configuration, instead of non-standard properties such as "brcm,function" and "brcm,group"
- Use real function names like "spi0", "lcd", "key", and etc. instead of HW
specific mux names like "alt1", "alt2", "alt3", and etc.
- Add suffix "grp" to all group names
- Add support to allow individual pins to be muxed to GPIO function through
subsystem callbacks "gpio_request_enable" and "gpio_disable_free", and get rid of all GPIO groups
- Other minor improvements in the driver
Changes from v1:
- Fix a typo in device tree binding document
Ray Jui (4):
pinctrl: bcm: consolidate Broadcom pinctrl drivers
pinctrl: Broadcom Cygnus pinctrl device tree binding
pinctrl: cygnus: add initial IOMUX driver support
ARM: dts: enable IOMUX for Broadcom Cygnus
.../bindings/pinctrl/brcm,cygnus-pinmux.txt | 159 +++ arch/arm/boot/dts/bcm-cygnus.dtsi | 6 + drivers/pinctrl/Kconfig | 19 +- drivers/pinctrl/Makefile | 4 +- drivers/pinctrl/bcm/Kconfig | 34 + drivers/pinctrl/bcm/Makefile | 5 + drivers/pinctrl/bcm/pinctrl-bcm281xx.c | 1455 ++++++++++++++++++++ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 1072 ++++++++++++++ drivers/pinctrl/bcm/pinctrl-cygnus-mux.c | 1087 +++++++++++++++ drivers/pinctrl/pinctrl-bcm281xx.c | 1455 -------------------- drivers/pinctrl/pinctrl-bcm2835.c | 1072 -------------- 11 files changed, 3821 insertions(+), 2547 deletions(-) create mode 100644 Documentation/devicetree/bindings/pinctrl/brcm,cygnus-pinmux.txt create mode 100644 drivers/pinctrl/bcm/Kconfig create mode 100644 drivers/pinctrl/bcm/Makefile create mode 100644 drivers/pinctrl/bcm/pinctrl-bcm281xx.c create mode 100644 drivers/pinctrl/bcm/pinctrl-bcm2835.c create mode 100644 drivers/pinctrl/bcm/pinctrl-cygnus-mux.c delete mode 100644 drivers/pinctrl/pinctrl-bcm281xx.c delete mode 100644 drivers/pinctrl/pinctrl-bcm2835.c
Signature · 1 line
1.7.9.5
Ray Jui
maintainerPATCH v3 1/4 pinctrl: bcm: consolidate Broadcom pinctrl drivers
Consolidate Broadcom pinctrl drivers into drivers/pinctrl/bcm/*
--- drivers/pinctrl/Kconfig | 19 +- drivers/pinctrl/Makefile | 4 +- drivers/pinctrl/bcm/Kconfig | 21 + drivers/pinctrl/bcm/Makefile | 4 + drivers/pinctrl/bcm/pinctrl-bcm281xx.c | 1455 ++++++++++++++++++++++++++++++++ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 1072 +++++++++++++++++++++++ drivers/pinctrl/pinctrl-bcm281xx.c | 1455 -------------------------------- drivers/pinctrl/pinctrl-bcm2835.c | 1072 ----------------------- 8 files changed, 2555 insertions(+), 2547 deletions(-) create mode 100644 drivers/pinctrl/bcm/Kconfig create mode 100644 drivers/pinctrl/bcm/Makefile create mode 100644 drivers/pinctrl/bcm/pinctrl-bcm281xx.c create mode 100644 drivers/pinctrl/bcm/pinctrl-bcm2835.c delete mode 100644 drivers/pinctrl/pinctrl-bcm281xx.c delete mode 100644 drivers/pinctrl/pinctrl-bcm2835.c
drivers/pinctrl/Kconfig +1 -18
@@ -67,24 +67,6 @@ config PINCTRL_AT91 help Say Y here to enable the at91 pinctrl driver -config PINCTRL_BCM2835 - bool - select PINMUX - select PINCONF - -config PINCTRL_BCM281XX - bool "Broadcom BCM281xx pinctrl driver" - depends on OF && (ARCH_BCM_MOBILE || COMPILE_TEST) - select PINMUX - select PINCONF - select GENERIC_PINCONF - select REGMAP_MMIO - help - Say Y here to support Broadcom BCM281xx pinctrl driver, which is used - for the BCM281xx SoC family, including BCM11130, BCM11140, BCM11351, - BCM28145, and BCM28155 SoCs. This driver requires the pinctrl - framework. GPIO is provided by a separate GPIO driver. - config PINCTRL_LANTIQ bool depends on LANTIQ
@@ -191,6 +173,7 @@ config PINCTRL_PALMAS open drain configuration for the Palmas series devices like TPS65913, TPS80036 etc. +source "drivers/pinctrl/bcm/Kconfig" source "drivers/pinctrl/berlin/Kconfig" source "drivers/pinctrl/freescale/Kconfig" source "drivers/pinctrl/intel/Kconfig"
drivers/pinctrl/Makefile +2 -2
@@ -14,8 +14,6 @@ obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o -obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o -obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
@@ -36,6 +34,8 @@ obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o +obj-$(CONFIG_ARCH_BCM) += bcm/ +obj-$(CONFIG_ARCH_BCM2835) += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-y += freescale/ obj-$(CONFIG_X86) += intel/
drivers/pinctrl/bcm/Kconfig new file +21 -0
@@ -0,0 +1,21 @@ +# +# Broadcom pinctrl drivers +# + +config PINCTRL_BCM281XX + bool "Broadcom BCM281xx pinctrl driver" + depends on OF && (ARCH_BCM_MOBILE || COMPILE_TEST) + select PINMUX + select PINCONF + select GENERIC_PINCONF + select REGMAP_MMIO + help + Say Y here to support Broadcom BCM281xx pinctrl driver, which is used + for the BCM281xx SoC family, including BCM11130, BCM11140, BCM11351, + BCM28145, and BCM28155 SoCs. This driver requires the pinctrl + framework. GPIO is provided by a separate GPIO driver. + +config PINCTRL_BCM2835 + bool + select PINMUX + select PINCONF
drivers/pinctrl/bcm/Makefile new file +4 -0
@@ -0,0 +1,4 @@ +# Broadcom pinctrl support + +obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o +obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
drivers/pinctrl/bcm/pinctrl-bcm281xx.c new file +1455 -0
1,455 lines not on this page · raw message
drivers/pinctrl/bcm/pinctrl-bcm2835.c new file +1072 -0
1,072 lines not on this page · raw message
drivers/pinctrl/pinctrl-bcm281xx.c deleted +0 -1455
401 lines not on this page · raw message
drivers/pinctrl/pinctrl-bcm2835.c deleted +0 -1072
1,072 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.7.9.5
Part of the diff is not shown here. View the raw message.