I2C serial bus support
~~~~~~~~~~~~~~~~~~~~~~
The slaves behind I2C bus controller only need to add the ACPI IDs like
-with the platform and SPI drivers. However the I2C bus controller driver
-needs to call acpi_i2c_register_devices() after it has added the adapter.
-
-An I2C bus (controller) driver does:
-
- ...
- ret = i2c_add_numbered_adapter(adapter);
- if (ret)
- /* handle error */
-
- of_i2c_register_devices(adapter);
- /* Enumerate the slave devices behind this bus via ACPI */
- acpi_i2c_register_devices(adapter);
+with the platform and SPI drivers. The I2C core automatically enumerates
+any slave devices behind the controller device once the adapter is
+registered.
Below is an example of how to add ACPI support to the existing mpu3050
input driver:
* Freescale Inter IC (I2C) and High Speed Inter IC (HS-I2C) for i.MX
Required properties:
-- compatible : Should be "fsl,<chip>-i2c"
+- compatible :
+ - "fsl,imx1-i2c" for I2C compatible with the one integrated on i.MX1 SoC
+ - "fsl,imx21-i2c" for I2C compatible with the one integrated on i.MX21 SoC
+ - "fsl,vf610-i2c" for I2C compatible with the one integrated on Vybrid vf610 SoC
- reg : Should contain I2C/HS-I2C registers location and length
- interrupts : Should contain I2C/HS-I2C interrupt
- reg : Offset and length of the register set for the device
- compatible : Should be "marvell,mv64xxx-i2c" or "allwinner,sun4i-i2c"
+ or "marvell,mv78230-i2c"
- interrupts : The interrupt number
Optional properties :
interrupts = <29>;
clock-frequency = <100000>;
};
+
+For the Armada XP:
+
+ i2c@11000 {
+ compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c";
+ reg = <0x11000 0x100>;
+ interrupts = <29>;
+ clock-frequency = <100000>;
+ };
The ServerWorks Southbridges, the Intel 440MX, and the Victory66 are
identical to the PIIX4 in I2C/SMBus support.
-The AMD SB700 and SP5100 chipsets implement two PIIX4-compatible SMBus
-controllers. If your BIOS initializes the secondary controller, it will
-be detected by this driver as an "Auxiliary SMBus Host Controller".
+The AMD SB700, SB800, SP5100 and Hudson-2 chipsets implement two
+PIIX4-compatible SMBus controllers. If your BIOS initializes the
+secondary controller, it will be detected by this driver as
+an "Auxiliary SMBus Host Controller".
If you own Force CPCI735 motherboard or other OSB4 based systems you may need
to change the SMBus Interrupt Select register so the SMBus controller uses
Example (from omap2 h4):
-static struct i2c_board_info __initdata h4_i2c_board_info[] = {
+static struct i2c_board_info h4_i2c_board_info[] __initdata = {
{
I2C_BOARD_INFO("isp1301_omap", 0x2d),
.irq = OMAP_GPIO_IRQ(125),
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/of_gpio.h>
-#include <linux/of_i2c.h>
#include <linux/slab.h>
#include <linux/export.h>
This driver supports ACPI-controlled docking stations and removable
drive bays such as the IBM Ultrabay and the Dell Module Bay.
-config ACPI_I2C
- def_tristate I2C
- depends on I2C
- help
- ACPI I2C enumeration support.
-
config ACPI_PROCESSOR
tristate "Processor"
select THERMAL
obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
obj-$(CONFIG_ACPI_BGRT) += bgrt.o
-obj-$(CONFIG_ACPI_I2C) += acpi_i2c.o
# processor has its own "processor." module_param namespace
processor-y := processor_driver.o processor_throttling.o
+++ /dev/null
-/*
- * ACPI I2C enumeration support
- *
- * Copyright (C) 2012, Intel Corporation
- * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/acpi.h>
-#include <linux/device.h>
-#include <linux/export.h>
-#include <linux/i2c.h>
-#include <linux/ioport.h>
-
-ACPI_MODULE_NAME("i2c");
-
-static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
-{
- struct i2c_board_info *info = data;
-
- if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
- struct acpi_resource_i2c_serialbus *sb;
-
- sb = &ares->data.i2c_serial_bus;
- if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
- info->addr = sb->slave_address;
- if (sb->access_mode == ACPI_I2C_10BIT_MODE)
- info->flags |= I2C_CLIENT_TEN;
- }
- } else if (info->irq < 0) {
- struct resource r;
-
- if (acpi_dev_resource_interrupt(ares, 0, &r))
- info->irq = r.start;
- }
-
- /* Tell the ACPI core to skip this resource */
- return 1;
-}
-
-static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
- void *data, void **return_value)
-{
- struct i2c_adapter *adapter = data;
- struct list_head resource_list;
- struct i2c_board_info info;
- struct acpi_device *adev;
- int ret;
-
- if (acpi_bus_get_device(handle, &adev))
- return AE_OK;
- if (acpi_bus_get_status(adev) || !adev->status.present)
- return AE_OK;
-
- memset(&info, 0, sizeof(info));
- info.acpi_node.handle = handle;
- info.irq = -1;
-
- INIT_LIST_HEAD(&resource_list);
- ret = acpi_dev_get_resources(adev, &resource_list,
- acpi_i2c_add_resource, &info);
- acpi_dev_free_resource_list(&resource_list);
-
- if (ret < 0 || !info.addr)
- return AE_OK;
-
- strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
- if (!i2c_new_device(adapter, &info)) {
- dev_err(&adapter->dev,
- "failed to add I2C device %s from ACPI\n",
- dev_name(&adev->dev));
- }
-
- return AE_OK;
-}
-
-/**
- * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
- * @adapter: pointer to adapter
- *
- * Enumerate all I2C slave devices behind this adapter by walking the ACPI
- * namespace. When a device is found it will be added to the Linux device
- * model and bound to the corresponding ACPI handle.
- */
-void acpi_i2c_register_devices(struct i2c_adapter *adapter)
-{
- acpi_handle handle;
- acpi_status status;
-
- handle = ACPI_HANDLE(adapter->dev.parent);
- if (!handle)
- return;
-
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
- acpi_i2c_add_device, NULL,
- adapter, NULL);
- if (ACPI_FAILURE(status))
- dev_warn(&adapter->dev, "failed to enumerate I2C slaves\n");
-}
-EXPORT_SYMBOL_GPL(acpi_i2c_register_devices);
*/
#include <linux/i2c.h>
-#include <linux/of_i2c.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/consumer.h>
#include <drm/drm_encoder_slave.h>
*/
#include <linux/i2c.h>
-#include <linux/of_i2c.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
-#include <linux/of_i2c.h>
+#include <linux/i2c.h>
#include "drm.h"
config I2C_DAVINCI
tristate "DaVinci I2C driver"
- depends on ARCH_DAVINCI
+ depends on ARCH_DAVINCI || ARCH_KEYSTONE
help
Support for TI DaVinci I2C controller driver.
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_i2c.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/platform_data/dma-atmel.h>
return rc;
}
- of_i2c_register_devices(&dev->adapter);
-
dev_info(dev->dev, "AT91 i2c bus driver.\n");
return 0;
}
.functionality = bfin_twi_functionality,
};
+#ifdef CONFIG_PM_SLEEP
static int i2c_bfin_twi_suspend(struct device *dev)
{
struct bfin_twi_iface *iface = dev_get_drvdata(dev);
static SIMPLE_DEV_PM_OPS(i2c_bfin_twi_pm,
i2c_bfin_twi_suspend, i2c_bfin_twi_resume);
+#define I2C_BFIN_TWI_PM_OPS (&i2c_bfin_twi_pm)
+#else
+#define I2C_BFIN_TWI_PM_OPS NULL
+#endif
static int i2c_bfin_twi_probe(struct platform_device *pdev)
{
p_adap->timeout = 5 * HZ;
p_adap->retries = 3;
- rc = peripheral_request_list((unsigned short *)pdev->dev.platform_data,
- "i2c-bfin-twi");
+ rc = peripheral_request_list(
+ (unsigned short *)dev_get_platdata(&pdev->dev),
+ "i2c-bfin-twi");
if (rc) {
dev_err(&pdev->dev, "Can't setup pin mux!\n");
goto out_error_pin_mux;
free_irq(iface->irq, iface);
out_error_req_irq:
out_error_no_irq:
- peripheral_free_list((unsigned short *)pdev->dev.platform_data);
+ peripheral_free_list((unsigned short *)dev_get_platdata(&pdev->dev));
out_error_pin_mux:
iounmap(iface->regs_base);
out_error_ioremap:
i2c_del_adapter(&(iface->adap));
free_irq(iface->irq, iface);
- peripheral_free_list((unsigned short *)pdev->dev.platform_data);
+ peripheral_free_list((unsigned short *)dev_get_platdata(&pdev->dev));
iounmap(iface->regs_base);
kfree(iface);
.driver = {
.name = "i2c-bfin-twi",
.owner = THIS_MODULE,
- .pm = &i2c_bfin_twi_pm,
+ .pm = I2C_BFIN_TWI_PM_OPS,
},
};
chost->clk_gpio = of_get_gpio(dnode, 0);
chost->dat_gpio = of_get_gpio(dnode, 1);
chost->sel_gpio = of_get_gpio(dnode, 2);
- } else if (pdev->dev.platform_data) {
- struct i2c_cbus_platform_data *pdata = pdev->dev.platform_data;
+ } else if (dev_get_platdata(&pdev->dev)) {
+ struct i2c_cbus_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
chost->clk_gpio = pdata->clk_gpio;
chost->dat_gpio = pdata->dat_gpio;
chost->sel_gpio = pdata->sel_gpio;
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
-#include <linux/of_i2c.h>
#include <sysdev/fsl_soc.h>
#include <asm/cpm.h>
dev_dbg(&ofdev->dev, "hw routines for %s registered.\n",
cpm->adap.name);
- /*
- * register OF I2C devices
- */
- of_i2c_register_devices(&cpm->adap);
-
return 0;
out_shut:
cpm_i2c_shutdown(cpm);
#include <linux/slab.h>
#include <linux/cpufreq.h>
#include <linux/gpio.h>
-#include <linux/of_i2c.h>
#include <linux/of_device.h>
-
-#include <mach/hardware.h>
#include <linux/platform_data/i2c-davinci.h>
/* ----- global defines ----------------------------------------------- */
#endif
dev->dev = &pdev->dev;
dev->irq = irq->start;
- dev->pdata = dev->dev->platform_data;
+ dev->pdata = dev_get_platdata(&dev->dev);
platform_set_drvdata(pdev, dev);
if (!dev->pdata && pdev->dev.of_node) {
dev_err(&pdev->dev, "failure adding adapter\n");
goto err_unuse_clocks;
}
- of_i2c_register_devices(adap);
return 0;
47, /* tLOW = 4.7 us */
3, /* tf = 0.3 us */
0); /* No offset */
+
+ /* Allow platforms to specify the ideal HCNT and LCNT values */
+ if (dev->ss_hcnt && dev->ss_lcnt) {
+ hcnt = dev->ss_hcnt;
+ lcnt = dev->ss_lcnt;
+ }
dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
13, /* tLOW = 1.3 us */
3, /* tf = 0.3 us */
0); /* No offset */
+
+ if (dev->fs_hcnt && dev->fs_lcnt) {
+ hcnt = dev->fs_hcnt;
+ lcnt = dev->fs_lcnt;
+ }
dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
u32 addr = msgs[dev->msg_write_idx].addr;
u32 buf_len = dev->tx_buf_len;
u8 *buf = dev->tx_buf;
+ bool need_restart = false;
intr_mask = DW_IC_INTR_DEFAULT_MASK;
/* new i2c_msg */
buf = msgs[dev->msg_write_idx].buf;
buf_len = msgs[dev->msg_write_idx].len;
+
+ /* If both IC_EMPTYFIFO_HOLD_MASTER_EN and
+ * IC_RESTART_EN are set, we must manually
+ * set restart bit between messages.
+ */
+ if ((dev->master_cfg & DW_IC_CON_RESTART_EN) &&
+ (dev->msg_write_idx > 0))
+ need_restart = true;
}
tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR);
buf_len == 1)
cmd |= BIT(9);
+ if (need_restart) {
+ cmd |= BIT(10);
+ need_restart = false;
+ }
+
if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
/* avoid rx buffer overrun */
* @tx_fifo_depth: depth of the hardware tx fifo
* @rx_fifo_depth: depth of the hardware rx fifo
* @rx_outstanding: current master-rx elements in tx fifo
+ * @ss_hcnt: standard speed HCNT value
+ * @ss_lcnt: standard speed LCNT value
+ * @fs_hcnt: fast speed HCNT value
+ * @fs_lcnt: fast speed LCNT value
+ *
+ * HCNT and LCNT parameters can be used if the platform knows more accurate
+ * values than the one computed based only on the input clock frequency.
+ * Leave them to be %0 if not used.
*/
struct dw_i2c_dev {
struct device *dev;
unsigned int rx_fifo_depth;
int rx_outstanding;
u32 sda_hold_time;
+ u16 ss_hcnt;
+ u16 ss_lcnt;
+ u16 fs_hcnt;
+ u16 fs_lcnt;
};
#define ACCESS_SWAP 0x00000001
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/of.h>
-#include <linux/of_i2c.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
}
#ifdef CONFIG_ACPI
+static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
+ u16 *hcnt, u16 *lcnt, u32 *sda_hold)
+{
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ acpi_handle handle = ACPI_HANDLE(&pdev->dev);
+ union acpi_object *obj;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, method, NULL, &buf)))
+ return;
+
+ obj = (union acpi_object *)buf.pointer;
+ if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 3) {
+ const union acpi_object *objs = obj->package.elements;
+
+ *hcnt = (u16)objs[0].integer.value;
+ *lcnt = (u16)objs[1].integer.value;
+ if (sda_hold)
+ *sda_hold = (u32)objs[2].integer.value;
+ }
+
+ kfree(buf.pointer);
+}
+
static int dw_i2c_acpi_configure(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+ bool fs_mode = dev->master_cfg & DW_IC_CON_SPEED_FAST;
if (!ACPI_HANDLE(&pdev->dev))
return -ENODEV;
dev->adapter.nr = -1;
dev->tx_fifo_depth = 32;
dev->rx_fifo_depth = 32;
+
+ /*
+ * Try to get SDA hold time and *CNT values from an ACPI method if
+ * it exists for both supported speed modes.
+ */
+ dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt,
+ fs_mode ? NULL : &dev->sda_hold_time);
+ dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
+ fs_mode ? &dev->sda_hold_time : NULL);
+
return 0;
}
dev_err(&pdev->dev, "failure adding adapter\n");
return r;
}
- of_i2c_register_devices(adap);
- acpi_i2c_register_devices(adap);
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev);
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
#endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int dw_i2c_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume);
+#define DW_I2C_DEV_PM_OPS (&dw_i2c_dev_pm_ops)
+#else
+#define DW_I2C_DEV_PM_OPS NULL
+#endif
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:i2c_designware");
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(dw_i2c_of_match),
.acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
- .pm = &dw_i2c_dev_pm_ops,
+ .pm = DW_I2C_DEV_PM_OPS,
},
};
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
-#include <linux/of_i2c.h>
struct i2c_gpio_private_data {
struct i2c_adapter adap;
if (ret)
return ret;
} else {
- if (!pdev->dev.platform_data)
+ if (!dev_get_platdata(&pdev->dev))
return -ENXIO;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
sda_pin = pdata->sda_pin;
scl_pin = pdata->scl_pin;
}
pdata->scl_pin = scl_pin;
of_i2c_gpio_get_props(pdev->dev.of_node, pdata);
} else {
- memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
+ memcpy(pdata, dev_get_platdata(&pdev->dev), sizeof(*pdata));
}
if (pdata->sda_is_open_drain) {
if (ret)
goto err_add_bus;
- of_i2c_register_devices(adap);
-
platform_set_drvdata(pdev, priv);
dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/err.h>
-#include <linux/of_i2c.h>
#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
defined CONFIG_DMI
goto exit_free_irq;
}
- of_i2c_register_devices(&priv->adapter);
i801_probe_optional_slaves(priv);
/* We ignore errors - multiplexing is optional */
i801_add_mux(priv);
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/of_platform.h>
-#include <linux/of_i2c.h>
#include "i2c-ibm_iic.h"
dev_info(&ofdev->dev, "using %s mode\n",
dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
- /* Now register all the child nodes */
- of_i2c_register_devices(adap);
-
return 0;
error_cleanup:
* Copyright (C) 2007 RightHand Technologies, Inc.
* Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt>
*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
*/
/** Includes *******************************************************************
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_i2c.h>
#include <linux/platform_data/i2c-imx.h>
/** Defines ********************************************************************
/* Default value */
#define IMX_I2C_BIT_RATE 100000 /* 100kHz */
-/* IMX I2C registers */
+/* IMX I2C registers:
+ * the I2C register offset is different between SoCs,
+ * to provid support for all these chips, split the
+ * register offset into a fixed base address and a
+ * variable shift value, then the full register offset
+ * will be calculated by
+ * reg_off = ( reg_base_addr << reg_shift)
+ */
#define IMX_I2C_IADR 0x00 /* i2c slave address */
-#define IMX_I2C_IFDR 0x04 /* i2c frequency divider */
-#define IMX_I2C_I2CR 0x08 /* i2c control */
-#define IMX_I2C_I2SR 0x0C /* i2c status */
-#define IMX_I2C_I2DR 0x10 /* i2c transfer data */
+#define IMX_I2C_IFDR 0x01 /* i2c frequency divider */
+#define IMX_I2C_I2CR 0x02 /* i2c control */
+#define IMX_I2C_I2SR 0x03 /* i2c status */
+#define IMX_I2C_I2DR 0x04 /* i2c transfer data */
+
+#define IMX_I2C_REGSHIFT 2
+#define VF610_I2C_REGSHIFT 0
/* Bits of IMX I2C registers */
#define I2SR_RXAK 0x01
#define I2CR_IIEN 0x40
#define I2CR_IEN 0x80
+/* register bits different operating codes definition:
+ * 1) I2SR: Interrupt flags clear operation differ between SoCs:
+ * - write zero to clear(w0c) INT flag on i.MX,
+ * - but write one to clear(w1c) INT flag on Vybrid.
+ * 2) I2CR: I2C module enable operation also differ between SoCs:
+ * - set I2CR_IEN bit enable the module on i.MX,
+ * - but clear I2CR_IEN bit enable the module on Vybrid.
+ */
+#define I2SR_CLR_OPCODE_W0C 0x0
+#define I2SR_CLR_OPCODE_W1C (I2SR_IAL | I2SR_IIF)
+#define I2CR_IEN_OPCODE_0 0x0
+#define I2CR_IEN_OPCODE_1 I2CR_IEN
+
/** Variables ******************************************************************
*******************************************************************************/
*
* Duplicated divider values removed from list
*/
+struct imx_i2c_clk_pair {
+ u16 div;
+ u16 val;
+};
-static u16 __initdata i2c_clk_div[50][2] = {
+static struct imx_i2c_clk_pair imx_i2c_clk_div[] = {
{ 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 },
{ 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 },
{ 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 },
{ 3072, 0x1E }, { 3840, 0x1F }
};
+/* Vybrid VF610 clock divider, register value pairs */
+static struct imx_i2c_clk_pair vf610_i2c_clk_div[] = {
+ { 20, 0x00 }, { 22, 0x01 }, { 24, 0x02 }, { 26, 0x03 },
+ { 28, 0x04 }, { 30, 0x05 }, { 32, 0x09 }, { 34, 0x06 },
+ { 36, 0x0A }, { 40, 0x07 }, { 44, 0x0C }, { 48, 0x0D },
+ { 52, 0x43 }, { 56, 0x0E }, { 60, 0x45 }, { 64, 0x12 },
+ { 68, 0x0F }, { 72, 0x13 }, { 80, 0x14 }, { 88, 0x15 },
+ { 96, 0x19 }, { 104, 0x16 }, { 112, 0x1A }, { 128, 0x17 },
+ { 136, 0x4F }, { 144, 0x1C }, { 160, 0x1D }, { 176, 0x55 },
+ { 192, 0x1E }, { 208, 0x56 }, { 224, 0x22 }, { 228, 0x24 },
+ { 240, 0x1F }, { 256, 0x23 }, { 288, 0x5C }, { 320, 0x25 },
+ { 384, 0x26 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B },
+ { 576, 0x2C }, { 640, 0x2D }, { 768, 0x31 }, { 896, 0x32 },
+ { 960, 0x2F }, { 1024, 0x33 }, { 1152, 0x34 }, { 1280, 0x35 },
+ { 1536, 0x36 }, { 1792, 0x3A }, { 1920, 0x37 }, { 2048, 0x3B },
+ { 2304, 0x3C }, { 2560, 0x3D }, { 3072, 0x3E }, { 3584, 0x7A },
+ { 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E },
+};
+
enum imx_i2c_type {
IMX1_I2C,
IMX21_I2C,
+ VF610_I2C,
+};
+
+struct imx_i2c_hwdata {
+ enum imx_i2c_type devtype;
+ unsigned regshift;
+ struct imx_i2c_clk_pair *clk_div;
+ unsigned ndivs;
+ unsigned i2sr_clr_opcode;
+ unsigned i2cr_ien_opcode;
};
struct imx_i2c_struct {
unsigned int disable_delay;
int stopped;
unsigned int ifdr; /* IMX_I2C_IFDR */
- enum imx_i2c_type devtype;
+ const struct imx_i2c_hwdata *hwdata;
+};
+
+static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
+ .devtype = IMX1_I2C,
+ .regshift = IMX_I2C_REGSHIFT,
+ .clk_div = imx_i2c_clk_div,
+ .ndivs = ARRAY_SIZE(imx_i2c_clk_div),
+ .i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C,
+ .i2cr_ien_opcode = I2CR_IEN_OPCODE_1,
+
+};
+
+static const struct imx_i2c_hwdata imx21_i2c_hwdata = {
+ .devtype = IMX21_I2C,
+ .regshift = IMX_I2C_REGSHIFT,
+ .clk_div = imx_i2c_clk_div,
+ .ndivs = ARRAY_SIZE(imx_i2c_clk_div),
+ .i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C,
+ .i2cr_ien_opcode = I2CR_IEN_OPCODE_1,
+
+};
+
+static struct imx_i2c_hwdata vf610_i2c_hwdata = {
+ .devtype = VF610_I2C,
+ .regshift = VF610_I2C_REGSHIFT,
+ .clk_div = vf610_i2c_clk_div,
+ .ndivs = ARRAY_SIZE(vf610_i2c_clk_div),
+ .i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C,
+ .i2cr_ien_opcode = I2CR_IEN_OPCODE_0,
+
};
static struct platform_device_id imx_i2c_devtype[] = {
{
.name = "imx1-i2c",
- .driver_data = IMX1_I2C,
+ .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata,
}, {
.name = "imx21-i2c",
- .driver_data = IMX21_I2C,
+ .driver_data = (kernel_ulong_t)&imx21_i2c_hwdata,
}, {
/* sentinel */
}
MODULE_DEVICE_TABLE(platform, imx_i2c_devtype);
static const struct of_device_id i2c_imx_dt_ids[] = {
- { .compatible = "fsl,imx1-i2c", .data = &imx_i2c_devtype[IMX1_I2C], },
- { .compatible = "fsl,imx21-i2c", .data = &imx_i2c_devtype[IMX21_I2C], },
+ { .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
+ { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
+ { .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx)
{
- return i2c_imx->devtype == IMX1_I2C;
+ return i2c_imx->hwdata->devtype == IMX1_I2C;
+}
+
+static inline void imx_i2c_write_reg(unsigned int val,
+ struct imx_i2c_struct *i2c_imx, unsigned int reg)
+{
+ writeb(val, i2c_imx->base + (reg << i2c_imx->hwdata->regshift));
+}
+
+static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx,
+ unsigned int reg)
+{
+ return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift));
}
/** Functions for IMX I2C adapter driver ***************************************
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
while (1) {
- temp = readb(i2c_imx->base + IMX_I2C_I2SR);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
if (for_busy && (temp & I2SR_IBB))
break;
if (!for_busy && !(temp & I2SR_IBB))
static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
{
- if (readb(i2c_imx->base + IMX_I2C_I2SR) & I2SR_RXAK) {
+ if (imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR) & I2SR_RXAK) {
dev_dbg(&i2c_imx->adapter.dev, "<%s> No ACK\n", __func__);
return -EIO; /* No ACK */
}
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
clk_prepare_enable(i2c_imx->clk);
- writeb(i2c_imx->ifdr, i2c_imx->base + IMX_I2C_IFDR);
+ imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
/* Enable I2C controller */
- writeb(0, i2c_imx->base + IMX_I2C_I2SR);
- writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
+ imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
+ imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR);
/* Wait controller to be stable */
udelay(50);
/* Start I2C transaction */
- temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_MSTA;
- writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
result = i2c_imx_bus_busy(i2c_imx, 1);
if (result)
return result;
i2c_imx->stopped = 0;
temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
- writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
return result;
}
if (!i2c_imx->stopped) {
/* Stop I2C transaction */
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
- temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp &= ~(I2CR_MSTA | I2CR_MTX);
- writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
}
if (is_imx1_i2c(i2c_imx)) {
/*
}
/* Disable I2C controller */
- writeb(0, i2c_imx->base + IMX_I2C_I2CR);
+ temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
clk_disable_unprepare(i2c_imx->clk);
}
static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
unsigned int rate)
{
+ struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div;
unsigned int i2c_clk_rate;
unsigned int div;
int i;
/* Divider value calculation */
i2c_clk_rate = clk_get_rate(i2c_imx->clk);
div = (i2c_clk_rate + rate - 1) / rate;
- if (div < i2c_clk_div[0][0])
+ if (div < i2c_clk_div[0].div)
i = 0;
- else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
- i = ARRAY_SIZE(i2c_clk_div) - 1;
+ else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div)
+ i = i2c_imx->hwdata->ndivs - 1;
else
- for (i = 0; i2c_clk_div[i][0] < div; i++);
+ for (i = 0; i2c_clk_div[i].div < div; i++);
/* Store divider value */
- i2c_imx->ifdr = i2c_clk_div[i][1];
+ i2c_imx->ifdr = i2c_clk_div[i].val;
/*
* There dummy delay is calculated.
* This delay is used in I2C bus disable function
* to fix chip hardware bug.
*/
- i2c_imx->disable_delay = (500000U * i2c_clk_div[i][0]
+ i2c_imx->disable_delay = (500000U * i2c_clk_div[i].div
+ (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2);
/* dev_dbg() can't be used, because adapter is not yet registered */
dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
__func__, i2c_clk_rate, div);
dev_dbg(&i2c_imx->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
- __func__, i2c_clk_div[i][1], i2c_clk_div[i][0]);
+ __func__, i2c_clk_div[i].val, i2c_clk_div[i].div);
#endif
}
struct imx_i2c_struct *i2c_imx = dev_id;
unsigned int temp;
- temp = readb(i2c_imx->base + IMX_I2C_I2SR);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
if (temp & I2SR_IIF) {
/* save status register */
i2c_imx->i2csr = temp;
temp &= ~I2SR_IIF;
- writeb(temp, i2c_imx->base + IMX_I2C_I2SR);
+ temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF);
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
wake_up(&i2c_imx->queue);
return IRQ_HANDLED;
}
__func__, msgs->addr << 1);
/* write slave address */
- writeb(msgs->addr << 1, i2c_imx->base + IMX_I2C_I2DR);
+ imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
result = i2c_imx_trx_complete(i2c_imx);
if (result)
return result;
dev_dbg(&i2c_imx->adapter.dev,
"<%s> write byte: B%d=0x%X\n",
__func__, i, msgs->buf[i]);
- writeb(msgs->buf[i], i2c_imx->base + IMX_I2C_I2DR);
+ imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR);
result = i2c_imx_trx_complete(i2c_imx);
if (result)
return result;
__func__, (msgs->addr << 1) | 0x01);
/* write slave address */
- writeb((msgs->addr << 1) | 0x01, i2c_imx->base + IMX_I2C_I2DR);
+ imx_i2c_write_reg((msgs->addr << 1) | 0x01, i2c_imx, IMX_I2C_I2DR);
result = i2c_imx_trx_complete(i2c_imx);
if (result)
return result;
dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__);
/* setup bus to read data */
- temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp &= ~I2CR_MTX;
if (msgs->len - 1)
temp &= ~I2CR_TXAK;
- writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
- readb(i2c_imx->base + IMX_I2C_I2DR); /* dummy read */
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__);
controller from generating another clock cycle */
dev_dbg(&i2c_imx->adapter.dev,
"<%s> clear MSTA\n", __func__);
- temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp &= ~(I2CR_MSTA | I2CR_MTX);
- writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
i2c_imx_bus_busy(i2c_imx, 0);
i2c_imx->stopped = 1;
} else if (i == (msgs->len - 2)) {
dev_dbg(&i2c_imx->adapter.dev,
"<%s> set TXAK\n", __func__);
- temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_TXAK;
- writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
}
- msgs->buf[i] = readb(i2c_imx->base + IMX_I2C_I2DR);
+ msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
dev_dbg(&i2c_imx->adapter.dev,
"<%s> read byte: B%d=0x%X\n",
__func__, i, msgs->buf[i]);
if (i) {
dev_dbg(&i2c_imx->adapter.dev,
"<%s> repeated start\n", __func__);
- temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_RSTA;
- writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
result = i2c_imx_bus_busy(i2c_imx, 1);
if (result)
goto fail0;
"<%s> transfer message: %d\n", __func__, i);
/* write/read data */
#ifdef CONFIG_I2C_DEBUG_BUS
- temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
dev_dbg(&i2c_imx->adapter.dev, "<%s> CONTROL: IEN=%d, IIEN=%d, "
"MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n", __func__,
(temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0),
(temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0),
(temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0));
- temp = readb(i2c_imx->base + IMX_I2C_I2SR);
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
dev_dbg(&i2c_imx->adapter.dev,
"<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, "
"IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n", __func__,
&pdev->dev);
struct imx_i2c_struct *i2c_imx;
struct resource *res;
- struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
+ struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
void __iomem *base;
int irq, ret;
u32 bitrate;
}
if (of_id)
- pdev->id_entry = of_id->data;
- i2c_imx->devtype = pdev->id_entry->driver_data;
+ i2c_imx->hwdata = of_id->data;
+ else
+ i2c_imx->hwdata = (struct imx_i2c_hwdata *)
+ platform_get_device_id(pdev)->driver_data;
/* Setup i2c_imx driver structure */
strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
return PTR_ERR(i2c_imx->clk);
}
+ ret = clk_prepare_enable(i2c_imx->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "can't enable I2C clock\n");
+ return ret;
+ }
/* Request IRQ */
ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
pdev->name, i2c_imx);
i2c_imx_set_clk(i2c_imx, bitrate);
/* Set up chip registers to defaults */
- writeb(0, i2c_imx->base + IMX_I2C_I2CR);
- writeb(0, i2c_imx->base + IMX_I2C_I2SR);
+ imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
+ i2c_imx, IMX_I2C_I2CR);
+ imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
/* Add I2C adapter */
ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
return ret;
}
- of_i2c_register_devices(&i2c_imx->adapter);
-
/* Set up platform driver data */
platform_set_drvdata(pdev, i2c_imx);
+ clk_disable_unprepare(i2c_imx->clk);
dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq);
dev_dbg(&i2c_imx->adapter.dev, "device resources from 0x%x to 0x%x\n",
i2c_del_adapter(&i2c_imx->adapter);
/* setup chip registers to defaults */
- writeb(0, i2c_imx->base + IMX_I2C_IADR);
- writeb(0, i2c_imx->base + IMX_I2C_IFDR);
- writeb(0, i2c_imx->base + IMX_I2C_I2CR);
- writeb(0, i2c_imx->base + IMX_I2C_I2SR);
+ imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
+ imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
+ imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
+ imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
return 0;
}
DMA_BIT_MASK(32)) != 0)) {
dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n",
pdev);
+ err = -ENODEV;
goto fail;
}
}
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/of_platform.h>
-#include <linux/of_i2c.h>
#include <linux/slab.h>
+#include <linux/clk.h>
#include <linux/io.h>
#include <linux/fsl_devices.h>
#include <linux/i2c.h>
struct i2c_adapter adap;
int irq;
u32 real_clk;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
u8 fdr, dfsrr;
#endif
+ struct clk *clk_per;
};
struct mpc_i2c_divider {
static struct i2c_adapter mpc_ops = {
.owner = THIS_MODULE,
- .name = "MPC adapter",
.algo = &mpc_algo,
.timeout = HZ,
};
u32 clock = MPC_I2C_CLOCK_LEGACY;
int result = 0;
int plen;
+ struct resource res;
+ struct clk *clk;
+ int err;
match = of_match_device(mpc_i2c_of_match, &op->dev);
if (!match)
}
}
+ /*
+ * enable clock for the I2C peripheral (non fatal),
+ * keep a reference upon successful allocation
+ */
+ clk = devm_clk_get(&op->dev, NULL);
+ if (!IS_ERR(clk)) {
+ err = clk_prepare_enable(clk);
+ if (err) {
+ dev_err(&op->dev, "failed to enable clock\n");
+ goto fail_request;
+ } else {
+ i2c->clk_per = clk;
+ }
+ }
+
if (of_get_property(op->dev.of_node, "fsl,preserve-clocking", NULL)) {
clock = MPC_I2C_CLOCK_PRESERVE;
} else {
platform_set_drvdata(op, i2c);
i2c->adap = mpc_ops;
+ of_address_to_resource(op->dev.of_node, 0, &res);
+ scnprintf(i2c->adap.name, sizeof(i2c->adap.name),
+ "MPC adapter at 0x%llx", (unsigned long long)res.start);
i2c_set_adapdata(&i2c->adap, i2c);
i2c->adap.dev.parent = &op->dev;
i2c->adap.dev.of_node = of_node_get(op->dev.of_node);
dev_err(i2c->dev, "failed to add adapter\n");
goto fail_add;
}
- of_i2c_register_devices(&i2c->adap);
return result;
fail_add:
+ if (i2c->clk_per)
+ clk_disable_unprepare(i2c->clk_per);
free_irq(i2c->irq, i2c);
fail_request:
irq_dispose_mapping(i2c->irq);
i2c_del_adapter(&i2c->adap);
+ if (i2c->clk_per)
+ clk_disable_unprepare(i2c->clk_per);
+
if (i2c->irq)
free_irq(i2c->irq, i2c);
return 0;
};
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int mpc_i2c_suspend(struct device *dev)
{
struct mpc_i2c *i2c = dev_get_drvdata(dev);
return 0;
}
-SIMPLE_DEV_PM_OPS(mpc_i2c_pm_ops, mpc_i2c_suspend, mpc_i2c_resume);
+static SIMPLE_DEV_PM_OPS(mpc_i2c_pm_ops, mpc_i2c_suspend, mpc_i2c_resume);
+#define MPC_I2C_PM_OPS (&mpc_i2c_pm_ops)
+#else
+#define MPC_I2C_PM_OPS NULL
#endif
static const struct mpc_i2c_data mpc_i2c_data_512x = {
.owner = THIS_MODULE,
.name = DRV_NAME,
.of_match_table = mpc_i2c_of_match,
-#ifdef CONFIG_PM
- .pm = &mpc_i2c_pm_ops,
-#endif
+ .pm = MPC_I2C_PM_OPS,
},
};
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
-#include <linux/of_i2c.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/delay.h>
#define MV64XXX_I2C_ADDR_ADDR(val) ((val & 0x7f) << 1)
#define MV64XXX_I2C_BAUD_DIV_N(val) (val & 0x7)
#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8
#define MV64XXX_I2C_STATUS_NO_STATUS 0xf8
+/* Register defines (I2C bridge) */
+#define MV64XXX_I2C_REG_TX_DATA_LO 0xc0
+#define MV64XXX_I2C_REG_TX_DATA_HI 0xc4
+#define MV64XXX_I2C_REG_RX_DATA_LO 0xc8
+#define MV64XXX_I2C_REG_RX_DATA_HI 0xcc
+#define MV64XXX_I2C_REG_BRIDGE_CONTROL 0xd0
+#define MV64XXX_I2C_REG_BRIDGE_STATUS 0xd4
+#define MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE 0xd8
+#define MV64XXX_I2C_REG_BRIDGE_INTR_MASK 0xdC
+#define MV64XXX_I2C_REG_BRIDGE_TIMING 0xe0
+
+/* Bridge Control values */
+#define MV64XXX_I2C_BRIDGE_CONTROL_WR 0x00000001
+#define MV64XXX_I2C_BRIDGE_CONTROL_RD 0x00000002
+#define MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT 2
+#define MV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT 0x00001000
+#define MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT 13
+#define MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT 16
+#define MV64XXX_I2C_BRIDGE_CONTROL_ENABLE 0x00080000
+
+/* Bridge Status values */
+#define MV64XXX_I2C_BRIDGE_STATUS_ERROR 0x00000001
+#define MV64XXX_I2C_STATUS_OFFLOAD_ERROR 0xf0000001
+#define MV64XXX_I2C_STATUS_OFFLOAD_OK 0xf0000000
+
+
/* Driver states */
enum {
MV64XXX_I2C_STATE_INVALID,
enum {
MV64XXX_I2C_ACTION_INVALID,
MV64XXX_I2C_ACTION_CONTINUE,
+ MV64XXX_I2C_ACTION_OFFLOAD_SEND_START,
MV64XXX_I2C_ACTION_SEND_START,
MV64XXX_I2C_ACTION_SEND_RESTART,
+ MV64XXX_I2C_ACTION_OFFLOAD_RESTART,
MV64XXX_I2C_ACTION_SEND_ADDR_1,
MV64XXX_I2C_ACTION_SEND_ADDR_2,
MV64XXX_I2C_ACTION_SEND_DATA,
MV64XXX_I2C_ACTION_RCV_DATA,
MV64XXX_I2C_ACTION_RCV_DATA_STOP,
MV64XXX_I2C_ACTION_SEND_STOP,
+ MV64XXX_I2C_ACTION_OFFLOAD_SEND_STOP,
};
struct mv64xxx_i2c_regs {
spinlock_t lock;
struct i2c_msg *msg;
struct i2c_adapter adapter;
+ bool offload_enabled;
+/* 5us delay in order to avoid repeated start timing violation */
+ bool errata_delay;
};
static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
}
}
+static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data)
+{
+ unsigned long data_reg_hi = 0;
+ unsigned long data_reg_lo = 0;
+ unsigned long ctrl_reg;
+ struct i2c_msg *msg = drv_data->msgs;
+
+ drv_data->msg = msg;
+ drv_data->byte_posn = 0;
+ drv_data->bytes_left = msg->len;
+ drv_data->aborting = 0;
+ drv_data->rc = 0;
+ /* Only regular transactions can be offloaded */
+ if ((msg->flags & ~(I2C_M_TEN | I2C_M_RD)) != 0)
+ return -EINVAL;
+
+ /* Only 1-8 byte transfers can be offloaded */
+ if (msg->len < 1 || msg->len > 8)
+ return -EINVAL;
+
+ /* Build transaction */
+ ctrl_reg = MV64XXX_I2C_BRIDGE_CONTROL_ENABLE |
+ (msg->addr << MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT);
+
+ if ((msg->flags & I2C_M_TEN) != 0)
+ ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT;
+
+ if ((msg->flags & I2C_M_RD) == 0) {
+ u8 local_buf[8] = { 0 };
+
+ memcpy(local_buf, msg->buf, msg->len);
+ data_reg_lo = cpu_to_le32(*((u32 *)local_buf));
+ data_reg_hi = cpu_to_le32(*((u32 *)(local_buf+4)));
+
+ ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_WR |
+ (msg->len - 1) << MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT;
+
+ writel_relaxed(data_reg_lo,
+ drv_data->reg_base + MV64XXX_I2C_REG_TX_DATA_LO);
+ writel_relaxed(data_reg_hi,
+ drv_data->reg_base + MV64XXX_I2C_REG_TX_DATA_HI);
+
+ } else {
+ ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_RD |
+ (msg->len - 1) << MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT;
+ }
+
+ /* Execute transaction */
+ writel(ctrl_reg, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
+
+ return 0;
+}
+
+static void
+mv64xxx_i2c_update_offload_data(struct mv64xxx_i2c_data *drv_data)
+{
+ struct i2c_msg *msg = drv_data->msg;
+
+ if (msg->flags & I2C_M_RD) {
+ u32 data_reg_lo = readl(drv_data->reg_base +
+ MV64XXX_I2C_REG_RX_DATA_LO);
+ u32 data_reg_hi = readl(drv_data->reg_base +
+ MV64XXX_I2C_REG_RX_DATA_HI);
+ u8 local_buf[8] = { 0 };
+
+ *((u32 *)local_buf) = le32_to_cpu(data_reg_lo);
+ *((u32 *)(local_buf+4)) = le32_to_cpu(data_reg_hi);
+ memcpy(msg->buf, local_buf, msg->len);
+ }
+
+}
/*
*****************************************************************************
*
static void
mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
{
+ if (drv_data->offload_enabled) {
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_TIMING);
+ writel(0, drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
+ writel(0, drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_INTR_MASK);
+ }
+
writel(0, drv_data->reg_base + drv_data->reg_offsets.soft_reset);
writel(MV64XXX_I2C_BAUD_DIV_M(drv_data->freq_m) | MV64XXX_I2C_BAUD_DIV_N(drv_data->freq_n),
drv_data->reg_base + drv_data->reg_offsets.clock);
drv_data->rc = -ENXIO;
break;
+ case MV64XXX_I2C_STATUS_OFFLOAD_OK:
+ if (drv_data->send_stop || drv_data->aborting) {
+ drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_SEND_STOP;
+ drv_data->state = MV64XXX_I2C_STATE_IDLE;
+ } else {
+ drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_RESTART;
+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_RESTART;
+ }
+ break;
+
default:
dev_err(&drv_data->adapter.dev,
"mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, "
mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
{
switch(drv_data->action) {
+ case MV64XXX_I2C_ACTION_OFFLOAD_RESTART:
+ mv64xxx_i2c_update_offload_data(drv_data);
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
+ writel(0, drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
+ /* FALLTHRU */
case MV64XXX_I2C_ACTION_SEND_RESTART:
/* We should only get here if we have further messages */
BUG_ON(drv_data->num_msgs == 0);
- drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
- writel(drv_data->cntl_bits,
- drv_data->reg_base + drv_data->reg_offsets.control);
-
drv_data->msgs++;
drv_data->num_msgs--;
+ if (!(drv_data->offload_enabled &&
+ mv64xxx_i2c_offload_msg(drv_data))) {
+ drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
+ writel(drv_data->cntl_bits,
+ drv_data->reg_base + drv_data->reg_offsets.control);
- /* Setup for the next message */
- mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
+ /* Setup for the next message */
+ mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
+ }
+ if (drv_data->errata_delay)
+ udelay(5);
/*
* We're never at the start of the message here, and by this
drv_data->reg_base + drv_data->reg_offsets.control);
break;
+ case MV64XXX_I2C_ACTION_OFFLOAD_SEND_START:
+ if (!mv64xxx_i2c_offload_msg(drv_data))
+ break;
+ else
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
+ /* FALLTHRU */
case MV64XXX_I2C_ACTION_SEND_START:
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
drv_data->reg_base + drv_data->reg_offsets.control);
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
drv_data->reg_base + drv_data->reg_offsets.control);
drv_data->block = 0;
+ if (drv_data->errata_delay)
+ udelay(5);
+
wake_up(&drv_data->waitq);
break;
"mv64xxx_i2c_do_action: Invalid action: %d\n",
drv_data->action);
drv_data->rc = -EIO;
+
/* FALLTHRU */
case MV64XXX_I2C_ACTION_SEND_STOP:
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
drv_data->block = 0;
wake_up(&drv_data->waitq);
break;
+
+ case MV64XXX_I2C_ACTION_OFFLOAD_SEND_STOP:
+ mv64xxx_i2c_update_offload_data(drv_data);
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
+ writel(0, drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
+ drv_data->block = 0;
+ wake_up(&drv_data->waitq);
+ break;
}
}
irqreturn_t rc = IRQ_NONE;
spin_lock_irqsave(&drv_data->lock, flags);
+
+ if (drv_data->offload_enabled) {
+ while (readl(drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE)) {
+ int reg_status = readl(drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_STATUS);
+ if (reg_status & MV64XXX_I2C_BRIDGE_STATUS_ERROR)
+ status = MV64XXX_I2C_STATUS_OFFLOAD_ERROR;
+ else
+ status = MV64XXX_I2C_STATUS_OFFLOAD_OK;
+ mv64xxx_i2c_fsm(drv_data, status);
+ mv64xxx_i2c_do_action(drv_data);
+ rc = IRQ_HANDLED;
+ }
+ }
while (readl(drv_data->reg_base + drv_data->reg_offsets.control) &
MV64XXX_I2C_REG_CONTROL_IFLG) {
status = readl(drv_data->reg_base + drv_data->reg_offsets.status);
unsigned long flags;
spin_lock_irqsave(&drv_data->lock, flags);
- mv64xxx_i2c_prepare_for_io(drv_data, msg);
-
- drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
- drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+ if (drv_data->offload_enabled) {
+ drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_SEND_START;
+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+ } else {
+ mv64xxx_i2c_prepare_for_io(drv_data, msg);
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+ }
drv_data->send_stop = is_last;
drv_data->block = 1;
mv64xxx_i2c_do_action(drv_data);
static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
{ .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i},
{ .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
+ { .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
{}
};
MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
memcpy(&drv_data->reg_offsets, device->data, sizeof(drv_data->reg_offsets));
+ /*
+ * For controllers embedded in new SoCs activate the
+ * Transaction Generator support and the errata fix.
+ */
+ if (of_device_is_compatible(np, "marvell,mv78230-i2c")) {
+ drv_data->offload_enabled = true;
+ drv_data->errata_delay = true;
+ }
+
out:
return rc;
#endif
mv64xxx_i2c_probe(struct platform_device *pd)
{
struct mv64xxx_i2c_data *drv_data;
- struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data;
+ struct mv64xxx_i2c_pdata *pdata = dev_get_platdata(&pd->dev);
struct resource *r;
int rc;
drv_data->freq_n = pdata->freq_n;
drv_data->irq = platform_get_irq(pd, 0);
drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
+ drv_data->offload_enabled = false;
memcpy(&drv_data->reg_offsets, &mv64xxx_i2c_regs_mv64xxx, sizeof(drv_data->reg_offsets));
} else if (pd->dev.of_node) {
rc = mv64xxx_of_config(drv_data, &pd->dev);
goto exit_free_irq;
}
- of_i2c_register_devices(&drv_data->adapter);
-
return 0;
exit_free_irq:
#include <linux/stmp_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_i2c.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
uint32_t timing0;
uint32_t timing1;
+ uint32_t timing2;
/* DMA support components */
- struct dma_chan *dmach;
+ struct dma_chan *dmach;
uint32_t pio_data[2];
uint32_t addr_data;
struct scatterlist sg_io[2];
bool dma_read;
};
-static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
+static int mxs_i2c_reset(struct mxs_i2c_dev *i2c)
{
- stmp_reset_block(i2c->regs);
+ int ret = stmp_reset_block(i2c->regs);
+ if (ret)
+ return ret;
/*
* Configure timing for the I2C block. The I2C TIMING2 register has to
*/
writel(i2c->timing0, i2c->regs + MXS_I2C_TIMING0);
writel(i2c->timing1, i2c->regs + MXS_I2C_TIMING1);
- writel(0x00300030, i2c->regs + MXS_I2C_TIMING2);
+ writel(i2c->timing2, i2c->regs + MXS_I2C_TIMING2);
writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
+
+ return 0;
}
static void mxs_i2c_dma_finish(struct mxs_i2c_dev *i2c)
int stop)
{
struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
- int ret;
+ int ret, err;
int flags;
flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
i2c->cmd_err = 0;
if (0) { /* disable PIO mode until a proper fix is made */
ret = mxs_i2c_pio_setup_xfer(adap, msg, flags);
- if (ret)
- mxs_i2c_reset(i2c);
+ if (ret) {
+ err = mxs_i2c_reset(i2c);
+ if (err)
+ return err;
+ }
} else {
INIT_COMPLETION(i2c->cmd_complete);
ret = mxs_i2c_dma_setup_xfer(adap, msg, flags);
timeout:
dev_dbg(i2c->dev, "Timeout!\n");
mxs_i2c_dma_finish(i2c);
- mxs_i2c_reset(i2c);
+ ret = mxs_i2c_reset(i2c);
+ if (ret)
+ return ret;
+
return -ETIMEDOUT;
}
.functionality = mxs_i2c_func,
};
-static void mxs_i2c_derive_timing(struct mxs_i2c_dev *i2c, int speed)
+static void mxs_i2c_derive_timing(struct mxs_i2c_dev *i2c, uint32_t speed)
{
- /* The I2C block clock run at 24MHz */
+ /* The I2C block clock runs at 24MHz */
const uint32_t clk = 24000000;
- uint32_t base;
+ uint32_t divider;
uint16_t high_count, low_count, rcv_count, xmit_count;
+ uint32_t bus_free, leadin;
struct device *dev = i2c->dev;
- if (speed > 540000) {
- dev_warn(dev, "Speed too high (%d Hz), using 540 kHz\n", speed);
- speed = 540000;
- } else if (speed < 12000) {
- dev_warn(dev, "Speed too low (%d Hz), using 12 kHz\n", speed);
- speed = 12000;
+ divider = DIV_ROUND_UP(clk, speed);
+
+ if (divider < 25) {
+ /*
+ * limit the divider, so that min(low_count, high_count)
+ * is >= 1
+ */
+ divider = 25;
+ dev_warn(dev,
+ "Speed too high (%u.%03u kHz), using %u.%03u kHz\n",
+ speed / 1000, speed % 1000,
+ clk / divider / 1000, clk / divider % 1000);
+ } else if (divider > 1897) {
+ /*
+ * limit the divider, so that max(low_count, high_count)
+ * cannot exceed 1023
+ */
+ divider = 1897;
+ dev_warn(dev,
+ "Speed too low (%u.%03u kHz), using %u.%03u kHz\n",
+ speed / 1000, speed % 1000,
+ clk / divider / 1000, clk / divider % 1000);
}
/*
- * The timing derivation algorithm. There is no documentation for this
- * algorithm available, it was derived by using the scope and fiddling
- * with constants until the result observed on the scope was good enough
- * for 20kHz, 50kHz, 100kHz, 200kHz, 300kHz and 400kHz. It should be
- * possible to assume the algorithm works for other frequencies as well.
+ * The I2C spec specifies the following timing data:
+ * standard mode fast mode Bitfield name
+ * tLOW (SCL LOW period) 4700 ns 1300 ns
+ * tHIGH (SCL HIGH period) 4000 ns 600 ns
+ * tSU;DAT (data setup time) 250 ns 100 ns
+ * tHD;STA (START hold time) 4000 ns 600 ns
+ * tBUF (bus free time) 4700 ns 1300 ns
*
- * Note it was necessary to cap the frequency on both ends as it's not
- * possible to configure completely arbitrary frequency for the I2C bus
- * clock.
+ * The hardware (of the i.MX28 at least) seems to add 2 additional
+ * clock cycles to the low_count and 7 cycles to the high_count.
+ * This is compensated for by subtracting the respective constants
+ * from the values written to the timing registers.
*/
- base = ((clk / speed) - 38) / 2;
- high_count = base + 3;
- low_count = base - 3;
- rcv_count = (high_count * 3) / 4;
- xmit_count = low_count / 4;
+ if (speed > 100000) {
+ /* fast mode */
+ low_count = DIV_ROUND_CLOSEST(divider * 13, (13 + 6));
+ high_count = DIV_ROUND_CLOSEST(divider * 6, (13 + 6));
+ leadin = DIV_ROUND_UP(600 * (clk / 1000000), 1000);
+ bus_free = DIV_ROUND_UP(1300 * (clk / 1000000), 1000);
+ } else {
+ /* normal mode */
+ low_count = DIV_ROUND_CLOSEST(divider * 47, (47 + 40));
+ high_count = DIV_ROUND_CLOSEST(divider * 40, (47 + 40));
+ leadin = DIV_ROUND_UP(4700 * (clk / 1000000), 1000);
+ bus_free = DIV_ROUND_UP(4700 * (clk / 1000000), 1000);
+ }
+ rcv_count = high_count * 3 / 8;
+ xmit_count = low_count * 3 / 8;
+
+ dev_dbg(dev,
+ "speed=%u(actual %u) divider=%u low=%u high=%u xmit=%u rcv=%u leadin=%u bus_free=%u\n",
+ speed, clk / divider, divider, low_count, high_count,
+ xmit_count, rcv_count, leadin, bus_free);
+ low_count -= 2;
+ high_count -= 7;
i2c->timing0 = (high_count << 16) | rcv_count;
i2c->timing1 = (low_count << 16) | xmit_count;
+ i2c->timing2 = (bus_free << 16 | leadin);
}
static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
platform_set_drvdata(pdev, i2c);
/* Do reset to enforce correct startup after pinmuxing */
- mxs_i2c_reset(i2c);
+ err = mxs_i2c_reset(i2c);
+ if (err)
+ return err;
adap = &i2c->adapter;
strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name));
return err;
}
- of_i2c_register_devices(adap);
-
return 0;
}
#include <linux/pm_runtime.h>
#include <linux/platform_data/i2c-nomadik.h>
#include <linux/of.h>
-#include <linux/of_i2c.h>
#include <linux/pinctrl/consumer.h>
#define DRIVER_NAME "nmk-i2c"
static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret = 0;
- struct nmk_i2c_controller *pdata = adev->dev.platform_data;
+ struct nmk_i2c_controller *pdata = dev_get_platdata(&adev->dev);
struct device_node *np = adev->dev.of_node;
struct nmk_i2c_dev *dev;
struct i2c_adapter *adap;
goto err_add_adap;
}
- of_i2c_register_devices(adap);
-
pm_runtime_put(&adev->dev);
return 0;
struct resource *res;
int ret;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "no platform data\n");
return -EINVAL;
#include <linux/i2c-ocores.h>
#include <linux/slab.h>
#include <linux/io.h>
-#include <linux/of_i2c.h>
#include <linux/log2.h>
struct ocores_i2c {
int ret;
int i;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
if (!i2c)
return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c->base))
return PTR_ERR(i2c->base);
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (pdata) {
i2c->reg_shift = pdata->reg_shift;
i2c->reg_io_width = pdata->reg_io_width;
if (pdata) {
for (i = 0; i < pdata->num_devices; i++)
i2c_new_device(&i2c->adap, pdata->devices + i);
- } else {
- of_i2c_register_devices(&i2c->adap);
}
return 0;
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ocores_i2c_suspend(struct device *dev)
{
struct ocores_i2c *i2c = dev_get_drvdata(dev);
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_i2c.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/slab.h>
}
dev_info(i2c->dev, "version %s\n", DRV_VERSION);
- of_i2c_register_devices(&i2c->adap);
-
return 0;
out:
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_i2c.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/i2c-omap.h>
#include <linux/pm_runtime.h>
-#include <linux/pinctrl/consumer.h>
/* I2C controller revisions */
#define OMAP_I2C_OMAP1_REV_2 0x20
u16 syscstate;
u16 westate;
u16 errata;
-
- struct pinctrl *pins;
};
static const u8 reg_map_ip_v1[] = {
if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
if (msg->flags & I2C_M_IGNORE_NAK)
return 0;
- if (stop) {
- w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
- w |= OMAP_I2C_CON_STP;
- omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
- }
+
+ w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
return -EREMOTEIO;
}
return -EIO;
struct i2c_adapter *adap;
struct resource *mem;
const struct omap_i2c_bus_platform_data *pdata =
- pdev->dev.platform_data;
+ dev_get_platdata(&pdev->dev);
struct device_node *node = pdev->dev.of_node;
const struct of_device_id *match;
int irq;
dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
}
- dev->pins = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(dev->pins)) {
- if (PTR_ERR(dev->pins) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
-
- dev_warn(&pdev->dev, "did not get pins for i2c error: %li\n",
- PTR_ERR(dev->pins));
- dev->pins = NULL;
- }
-
dev->dev = &pdev->dev;
dev->irq = irq;
dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr,
major, minor, dev->speed);
- of_i2c_register_devices(adap);
-
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
struct i2c_pca_pf_data *i2c;
struct resource *res;
struct i2c_pca9564_pf_platform_data *platform_data =
- pdev->dev.platform_data;
+ dev_get_platdata(&pdev->dev);
int ret = 0;
int irq;
}
static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
- const struct pci_device_id *id)
+ const struct pci_device_id *id, u8 aux)
{
unsigned short piix4_smba;
unsigned short smba_idx = 0xcd6;
- u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c;
+ u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en;
/* SB800 and later SMBus does not support forcing address */
if (force || force_addr) {
}
/* Determine the address of the SMBus areas */
+ smb_en = (aux) ? 0x28 : 0x2c;
+
if (!request_region(smba_idx, 2, "smba_idx")) {
dev_err(&PIIX4_dev->dev, "SMBus base address index region "
"0x%x already in use!\n", smba_idx);
return -EBUSY;
}
+ /* Aux SMBus does not support IRQ information */
+ if (aux) {
+ dev_info(&PIIX4_dev->dev,
+ "SMBus Host Controller at 0x%x\n", piix4_smba);
+ return piix4_smba;
+ }
+
/* Request the SMBus I2C bus config region */
if (!request_region(piix4_smba + i2ccfg_offset, 1, "i2ccfg")) {
dev_err(&PIIX4_dev->dev, "SMBus I2C bus config region "
dev->revision >= 0x40) ||
dev->vendor == PCI_VENDOR_ID_AMD)
/* base address location etc changed in SB800 */
- retval = piix4_setup_sb800(dev, id);
+ retval = piix4_setup_sb800(dev, id, 0);
else
retval = piix4_setup(dev, id);
return retval;
/* Check for auxiliary SMBus on some AMD chipsets */
+ retval = -ENODEV;
+
if (dev->vendor == PCI_VENDOR_ID_ATI &&
- dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
- dev->revision < 0x40) {
- retval = piix4_setup_aux(dev, id, 0x58);
- if (retval > 0) {
- /* Try to add the aux adapter if it exists,
- * piix4_add_adapter will clean up if this fails */
- piix4_add_adapter(dev, retval, &piix4_aux_adapter);
+ dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS) {
+ if (dev->revision < 0x40) {
+ retval = piix4_setup_aux(dev, id, 0x58);
+ } else {
+ /* SB800 added aux bus too */
+ retval = piix4_setup_sb800(dev, id, 1);
}
}
+ if (dev->vendor == PCI_VENDOR_ID_AMD &&
+ dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) {
+ retval = piix4_setup_sb800(dev, id, 1);
+ }
+
+ if (retval > 0) {
+ /* Try to add the aux adapter if it exists,
+ * piix4_add_adapter will clean up if this fails */
+ piix4_add_adapter(dev, retval, &piix4_aux_adapter);
+ }
+
return 0;
}
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/slab.h>
-#include <linux/of_i2c.h>
#define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */
#define I2C_PNX_SPEED_KHZ_DEFAULT 100
.functionality = i2c_pnx_func,
};
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int i2c_pnx_controller_suspend(struct device *dev)
{
struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev);
alg_data->irq = platform_get_irq(pdev, 0);
if (alg_data->irq < 0) {
dev_err(&pdev->dev, "Failed to get IRQ from platform resource\n");
- goto out_irq;
+ ret = alg_data->irq;
+ goto out_clock;
}
ret = request_irq(alg_data->irq, i2c_pnx_interrupt,
0, pdev->name, alg_data);
goto out_irq;
}
- of_i2c_register_devices(&alg_data->adapter);
-
dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
alg_data->adapter.name, res->start, alg_data->irq);
static int i2c_powermac_probe(struct platform_device *dev)
{
- struct pmac_i2c_bus *bus = dev->dev.platform_data;
+ struct pmac_i2c_bus *bus = dev_get_platdata(&dev->dev);
struct device_node *parent = NULL;
struct i2c_adapter *adapter;
const char *basename;
adapter->algo = &i2c_powermac_algorithm;
i2c_set_adapdata(adapter, bus);
adapter->dev.parent = &dev->dev;
- adapter->dev.of_node = dev->dev.of_node;
+
+ /* Clear of_node to skip automatic registration of i2c child nodes */
+ adapter->dev.of_node = NULL;
rc = i2c_add_adapter(adapter);
if (rc) {
printk(KERN_ERR "i2c-powermac: Adapter %s registration "
"failed\n", adapter->name);
memset(adapter, 0, sizeof(*adapter));
+ return rc;
}
printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
- /* Cannot use of_i2c_register_devices() due to Apple device-tree
- * funkyness
- */
+ /* Use custom child registration due to Apple device-tree funkyness */
+ adapter->dev.of_node = dev->dev.of_node;
i2c_powermac_register_devices(adapter, bus);
- return rc;
+ return 0;
}
static struct platform_driver i2c_powermac_driver = {
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int puv3_i2c_suspend(struct device *dev)
{
int poll_count;
#include <linux/i2c-pxa.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_i2c.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
#define ICR_SADIE (1 << 13) /* slave address detected int enable */
#define ICR_UR (1 << 14) /* unit reset */
#define ICR_FM (1 << 15) /* fast mode */
+#define ICR_HS (1 << 16) /* High Speed mode */
+#define ICR_GPIOEN (1 << 19) /* enable GPIO mode for SCL in HS */
#define ISR_RWM (1 << 0) /* read/write mode */
#define ISR_ACKNAK (1 << 1) /* ack/nak status */
int irq;
unsigned int use_pio :1;
unsigned int fast_mode :1;
+ unsigned int high_mode:1;
+ unsigned char master_code;
+ unsigned long rate;
+ bool highmode_enter;
};
#define _IBMR(i2c) ((i2c)->reg_ibmr)
/* set control register values */
writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c));
+ writel(readl(_ICR(i2c)) | (i2c->high_mode ? ICR_HS : 0), _ICR(i2c));
#ifdef CONFIG_I2C_PXA_SLAVE
dev_info(&i2c->adap.dev, "Enabling slave mode\n");
return 0;
}
+/*
+ * PXA I2C send master code
+ * 1. Load master code to IDBR and send it.
+ * Note for HS mode, set ICR [GPIOEN].
+ * 2. Wait until win arbitration.
+ */
+static int i2c_pxa_send_mastercode(struct pxa_i2c *i2c)
+{
+ u32 icr;
+ long timeout;
+
+ spin_lock_irq(&i2c->lock);
+ i2c->highmode_enter = true;
+ writel(i2c->master_code, _IDBR(i2c));
+
+ icr = readl(_ICR(i2c)) & ~(ICR_STOP | ICR_ALDIE);
+ icr |= ICR_GPIOEN | ICR_START | ICR_TB | ICR_ITEIE;
+ writel(icr, _ICR(i2c));
+
+ spin_unlock_irq(&i2c->lock);
+ timeout = wait_event_timeout(i2c->wait,
+ i2c->highmode_enter == false, HZ * 1);
+
+ i2c->highmode_enter = false;
+
+ return (timeout == 0) ? I2C_RETRY : 0;
+}
+
static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c,
struct i2c_msg *msg, int num)
{
goto out;
}
+ if (i2c->high_mode) {
+ ret = i2c_pxa_send_mastercode(i2c);
+ if (ret) {
+ dev_err(&i2c->adap.dev, "i2c_pxa_send_mastercode timeout\n");
+ goto out;
+ }
+ }
+
spin_lock_irq(&i2c->lock);
i2c->msg = msg;
i2c_pxa_slave_txempty(i2c, isr);
if (isr & ISR_IRF)
i2c_pxa_slave_rxfull(i2c, isr);
- } else if (i2c->msg) {
+ } else if (i2c->msg && (!i2c->highmode_enter)) {
if (isr & ISR_ITE)
i2c_pxa_irq_txempty(i2c, isr);
if (isr & ISR_IRF)
i2c_pxa_irq_rxfull(i2c, isr);
+ } else if ((isr & ISR_ITE) && i2c->highmode_enter) {
+ i2c->highmode_enter = false;
+ wake_up(&i2c->wait);
} else {
i2c_pxa_scream_blue_murder(i2c, "spurious irq");
}
struct pxa_i2c *i2c,
enum pxa_i2c_types *i2c_types)
{
- struct i2c_pxa_platform_data *plat = pdev->dev.platform_data;
+ struct i2c_pxa_platform_data *plat = dev_get_platdata(&pdev->dev);
const struct platform_device_id *id = platform_get_device_id(pdev);
*i2c_types = id->driver_data;
if (plat) {
i2c->use_pio = plat->use_pio;
i2c->fast_mode = plat->fast_mode;
+ i2c->high_mode = plat->high_mode;
+ i2c->master_code = plat->master_code;
+ if (!i2c->master_code)
+ i2c->master_code = 0xe;
+ i2c->rate = plat->rate;
}
return 0;
}
static int i2c_pxa_probe(struct platform_device *dev)
{
- struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
+ struct i2c_pxa_platform_data *plat = dev_get_platdata(&dev->dev);
enum pxa_i2c_types i2c_type;
struct pxa_i2c *i2c;
struct resource *res = NULL;
i2c->irq = irq;
i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
+ i2c->highmode_enter = false;
if (plat) {
#ifdef CONFIG_I2C_PXA_SLAVE
i2c->adap.class = plat->class;
}
+ if (i2c->high_mode) {
+ if (i2c->rate) {
+ clk_set_rate(i2c->clk, i2c->rate);
+ pr_info("i2c: <%s> set rate to %ld\n",
+ i2c->adap.name, clk_get_rate(i2c->clk));
+ } else
+ pr_warn("i2c: <%s> clock rate not set\n",
+ i2c->adap.name);
+ }
+
clk_prepare_enable(i2c->clk);
if (i2c->use_pio) {
printk(KERN_INFO "I2C: Failed to add bus\n");
goto eadapt;
}
- of_i2c_register_devices(&i2c->adap);
platform_set_drvdata(dev, i2c);
#define ID_ARBLOST (1 << 3)
#define ID_NACK (1 << 4)
+enum rcar_i2c_type {
+ I2C_RCAR_H1,
+ I2C_RCAR_H2,
+};
+
struct rcar_i2c_priv {
void __iomem *io;
struct i2c_adapter adap;
int irq;
u32 icccr;
u32 flags;
+ enum rcar_i2c_type devtype;
};
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
u32 scgd, cdf;
u32 round, ick;
u32 scl;
+ u32 cdf_width;
if (!clkp) {
dev_err(dev, "there is no peripheral_clk\n");
return -EIO;
}
+ switch (priv->devtype) {
+ case I2C_RCAR_H1:
+ cdf_width = 2;
+ break;
+ case I2C_RCAR_H2:
+ cdf_width = 3;
+ break;
+ default:
+ dev_err(dev, "device type error\n");
+ return -EIO;
+ }
+
/*
* calculate SCL clock
* see
* clkp : peripheral_clk
* F[] : integer up-valuation
*/
- for (cdf = 0; cdf < 4; cdf++) {
+ for (cdf = 0; cdf < (1 << cdf_width); cdf++) {
ick = clk_get_rate(clkp) / (1 + cdf);
if (ick < 20000000)
goto ick_find;
/*
* keep icccr value
*/
- priv->icccr = (scgd << 2 | cdf);
+ priv->icccr = (scgd << (cdf_width) | cdf);
return 0;
}
static int rcar_i2c_probe(struct platform_device *pdev)
{
- struct i2c_rcar_platform_data *pdata = pdev->dev.platform_data;
+ struct i2c_rcar_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct rcar_i2c_priv *priv;
struct i2c_adapter *adap;
struct resource *res;
bus_speed = 100000; /* default 100 kHz */
if (pdata && pdata->bus_speed)
bus_speed = pdata->bus_speed;
+
+ priv->devtype = platform_get_device_id(pdev)->driver_data;
+
ret = rcar_i2c_clock_calculate(priv, bus_speed, dev);
if (ret < 0)
return ret;
return 0;
}
+static struct platform_device_id rcar_i2c_id_table[] = {
+ { "i2c-rcar", I2C_RCAR_H1 },
+ { "i2c-rcar_h1", I2C_RCAR_H1 },
+ { "i2c-rcar_h2", I2C_RCAR_H2 },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, rcar_i2c_id_table);
+
static struct platform_driver rcar_i2c_driver = {
.driver = {
.name = "i2c-rcar",
},
.probe = rcar_i2c_probe,
.remove = rcar_i2c_remove,
+ .id_table = rcar_i2c_id_table,
};
module_platform_driver(rcar_i2c_driver);
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/io.h>
-#include <linux/of_i2c.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
int ret;
if (!pdev->dev.of_node) {
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "no platform data\n");
return -EINVAL;
return ret;
}
- of_i2c_register_devices(&i2c->adap);
platform_set_drvdata(pdev, i2c);
pm_runtime_enable(&pdev->dev);
clock = 0;
bus_num = -1;
- if (dev->dev.platform_data) {
- struct s6_i2c_platform_data *pdata = dev->dev.platform_data;
+ if (dev_get_platdata(&dev->dev)) {
+ struct s6_i2c_platform_data *pdata =
+ dev_get_platdata(&dev->dev);
bus_num = pdata->bus_num;
clock = pdata->clock;
}
struct cami2c *id;
int ret;
- pd = pdev->dev.platform_data;
+ pd = dev_get_platdata(&pdev->dev);
if (!pd) {
dev_err(&pdev->dev, "no platform_data!\n");
ret = -ENODEV;
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
-#include <linux/of_i2c.h>
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
static int sh_mobile_i2c_probe(struct platform_device *dev)
{
- struct i2c_sh_mobile_platform_data *pdata = dev->dev.platform_data;
+ struct i2c_sh_mobile_platform_data *pdata = dev_get_platdata(&dev->dev);
struct sh_mobile_i2c_data *pd;
struct i2c_adapter *adap;
struct resource *res;
"I2C adapter %d with bus speed %lu Hz (L/H=%x/%x)\n",
adap->nr, pd->bus_speed, pd->iccl, pd->icch);
- of_i2c_register_devices(adap);
return 0;
err_all:
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
-#include <linux/of_i2c.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#define SIRFSOC_I2C_START BIT(7)
#define SIRFSOC_I2C_DEFAULT_SPEED 100000
+#define SIRFSOC_I2C_ERR_NOACK 1
+#define SIRFSOC_I2C_ERR_TIMEOUT 2
struct sirfsoc_i2c {
void __iomem *base;
if (i2c_stat & SIRFSOC_I2C_STAT_ERR) {
/* Error conditions */
- siic->err_status = 1;
+ siic->err_status = SIRFSOC_I2C_ERR_NOACK;
writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS);
if (i2c_stat & SIRFSOC_I2C_STAT_NACK)
- dev_err(&siic->adapter.dev, "ACK not received\n");
+ dev_dbg(&siic->adapter.dev, "ACK not received\n");
else
dev_err(&siic->adapter.dev, "I2C error\n");
+ /*
+ * Due to hardware ANOMALY, we need to reset I2C earlier after
+ * we get NOACK while accessing non-existing clients, otherwise
+ * we will get errors even we access existing clients later
+ */
+ writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
+ siic->base + SIRFSOC_I2C_CTRL);
+ while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+ cpu_relax();
+
complete(&siic->done);
} else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) {
/* CMD buffer execution complete */
if (msg->flags & I2C_M_RD)
addr |= 1;
+ /* Reverse direction bit */
+ if (msg->flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+
writel(addr, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
}
u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL);
/* timeout waiting for the xfer to finish or fail */
int timeout = msecs_to_jiffies((msg->len + 1) * 50);
- int ret = 0;
i2c_sirfsoc_set_address(siic, msg);
i2c_sirfsoc_queue_cmd(siic);
if (wait_for_completion_timeout(&siic->done, timeout) == 0) {
- siic->err_status = 1;
+ siic->err_status = SIRFSOC_I2C_ERR_TIMEOUT;
dev_err(&siic->adapter.dev, "Transfer timeout\n");
}
siic->base + SIRFSOC_I2C_CTRL);
writel(0, siic->base + SIRFSOC_I2C_CMD_START);
- if (siic->err_status) {
+ /* i2c control doesn't response, reset it */
+ if (siic->err_status == SIRFSOC_I2C_ERR_TIMEOUT) {
writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
siic->base + SIRFSOC_I2C_CTRL);
while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
cpu_relax();
-
- ret = -EIO;
}
-
- return ret;
+ return siic->err_status ? -EAGAIN : 0;
}
static u32 i2c_sirfsoc_func(struct i2c_adapter *adap)
adap->algo = &i2c_sirfsoc_algo;
adap->algo_data = siic;
+ adap->retries = 3;
adap->dev.of_node = pdev->dev.of_node;
adap->dev.parent = &pdev->dev;
if (bitrate < 100000)
regval =
- (2 * ctrl_speed) / (2 * bitrate * 11);
+ (2 * ctrl_speed) / (bitrate * 11);
else
regval = ctrl_speed / (bitrate * 5);
clk_disable(clk);
- of_i2c_register_devices(adap);
-
dev_info(&pdev->dev, " I2C adapter ready to operate\n");
return 0;
clk_enable(siic->clk);
writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+ while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+ cpu_relax();
writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
siic->base + SIRFSOC_I2C_CTRL);
writel(siic->clk_div, siic->base + SIRFSOC_I2C_CLK_CTRL);
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
-#include <linux/of_i2c.h>
/* the name of this kernel module */
#define NAME "stu300"
dev->pdev = pdev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENOENT;
-
dev->virtbase = devm_ioremap_resource(&pdev->dev, res);
dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual "
"base %p\n", bus_nr, dev->virtbase);
platform_set_drvdata(pdev, dev);
dev_info(&pdev->dev, "ST DDC I2C @ %p, irq %d\n",
dev->virtbase, dev->irq);
- of_i2c_register_devices(adap);
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int stu300_suspend(struct device *device)
{
struct stu300_dev *dev = dev_get_drvdata(device);
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/of_i2c.h>
#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/clk/tegra.h>
return ret;
}
- of_i2c_register_devices(&i2c_dev->adapter);
-
return 0;
}
static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{
- unsigned char status;
+ unsigned char *pstatus;
struct i2c_msg *pmsg;
- int i;
+ int i, ret;
dev_dbg(&adapter->dev, "master xfer %d messages:\n", num);
+ pstatus = kmalloc(sizeof(*pstatus), GFP_KERNEL);
+ if (!pstatus)
+ return -ENOMEM;
+
for (i = 0 ; i < num ; i++) {
int cmd = CMD_I2C_IO;
pmsg->buf, pmsg->len) != pmsg->len) {
dev_err(&adapter->dev,
"failure reading data\n");
- return -EREMOTEIO;
+ ret = -EREMOTEIO;
+ goto out;
}
} else {
/* write data */
pmsg->buf, pmsg->len) != pmsg->len) {
dev_err(&adapter->dev,
"failure writing data\n");
- return -EREMOTEIO;
+ ret = -EREMOTEIO;
+ goto out;
}
}
/* read status */
- if (usb_read(adapter, CMD_GET_STATUS, 0, 0, &status, 1) != 1) {
+ if (usb_read(adapter, CMD_GET_STATUS, 0, 0, pstatus, 1) != 1) {
dev_err(&adapter->dev, "failure reading status\n");
- return -EREMOTEIO;
+ ret = -EREMOTEIO;
+ goto out;
}
- dev_dbg(&adapter->dev, " status = %d\n", status);
- if (status == STATUS_ADDRESS_NAK)
- return -EREMOTEIO;
+ dev_dbg(&adapter->dev, " status = %d\n", *pstatus);
+ if (*pstatus == STATUS_ADDRESS_NAK) {
+ ret = -EREMOTEIO;
+ goto out;
+ }
}
- return i;
+ ret = i;
+out:
+ kfree(pstatus);
+ return ret;
}
static u32 usb_func(struct i2c_adapter *adapter)
{
- __le32 func;
+ __le32 *pfunc;
+ u32 ret;
+
+ pfunc = kmalloc(sizeof(*pfunc), GFP_KERNEL);
/* get functionality from adapter */
- if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) !=
- sizeof(func)) {
+ if (!pfunc || usb_read(adapter, CMD_GET_FUNC, 0, 0, pfunc,
+ sizeof(*pfunc)) != sizeof(*pfunc)) {
dev_err(&adapter->dev, "failure reading functionality\n");
- return 0;
+ ret = 0;
+ goto out;
}
- return le32_to_cpu(func);
+ ret = le32_to_cpup(pfunc);
+out:
+ kfree(pfunc);
+ return ret;
}
/* This is the actual algorithm we define */
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/io.h>
-#include <linux/of_i2c.h>
#define I2C_CONTROL 0x00
#define I2C_CONTROLS 0x00
ret = i2c_bit_add_numbered_bus(&i2c->adap);
if (ret >= 0) {
platform_set_drvdata(dev, i2c);
- of_i2c_register_devices(&i2c->adap);
return 0;
}
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_i2c.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
platform_set_drvdata(pdev, i2c_dev);
- of_i2c_register_devices(adap);
-
return 0;
}
#include <linux/i2c-xiic.h>
#include <linux/io.h>
#include <linux/slab.h>
-#include <linux/of_i2c.h>
#define DRIVER_NAME "xiic-i2c"
if (irq < 0)
goto resource_missing;
- pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data;
+ pdata = (struct xiic_i2c_platform_data *)dev_get_platdata(&pdev->dev);
i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
if (!i2c)
i2c_new_device(&i2c->adap, pdata->devices + i);
}
- of_i2c_register_devices(&i2c->adap);
-
return 0;
add_adapter_failed:
SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and
Jean Delvare <khali@linux-fr.org>
Mux support by Rodolfo Giometti <giometti@enneenne.com> and
- Michael Lawnick <michael.lawnick.ext@nsn.com> */
+ Michael Lawnick <michael.lawnick.ext@nsn.com>
+ OF support is copyright (c) 2008 Jochen Friedrich <jochen@scram.de>
+ (based on a previous patch from Jon Smirl <jonsmirl@gmail.com>) and
+ (c) 2013 Wolfram Sang <wsa@the-dreams.de>
+ */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/idr.h>
#include <linux/mutex.h>
+#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/completion.h>
#include <linux/hardirq.h>
#include <linux/irqflags.h>
up_read(&__i2c_board_lock);
}
+/* OF support code */
+
+#if IS_ENABLED(CONFIG_OF)
+static void of_i2c_register_devices(struct i2c_adapter *adap)
+{
+ void *result;
+ struct device_node *node;
+
+ /* Only register child devices if the adapter has a node pointer set */
+ if (!adap->dev.of_node)
+ return;
+
+ dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
+
+ for_each_available_child_of_node(adap->dev.of_node, node) {
+ struct i2c_board_info info = {};
+ struct dev_archdata dev_ad = {};
+ const __be32 *addr;
+ int len;
+
+ dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
+
+ if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
+ dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
+ node->full_name);
+ continue;
+ }
+
+ addr = of_get_property(node, "reg", &len);
+ if (!addr || (len < sizeof(int))) {
+ dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
+ node->full_name);
+ continue;
+ }
+
+ info.addr = be32_to_cpup(addr);
+ if (info.addr > (1 << 10) - 1) {
+ dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
+ info.addr, node->full_name);
+ continue;
+ }
+
+ info.irq = irq_of_parse_and_map(node, 0);
+ info.of_node = of_node_get(node);
+ info.archdata = &dev_ad;
+
+ if (of_get_property(node, "wakeup-source", NULL))
+ info.flags |= I2C_CLIENT_WAKE;
+
+ request_module("%s%s", I2C_MODULE_PREFIX, info.type);
+
+ result = i2c_new_device(adap, &info);
+ if (result == NULL) {
+ dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
+ node->full_name);
+ of_node_put(node);
+ irq_dispose_mapping(info.irq);
+ continue;
+ }
+ }
+}
+
+static int of_dev_node_match(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+/* must call put_device() when done with returned i2c_client device */
+struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
+{
+ struct device *dev;
+
+ dev = bus_find_device(&i2c_bus_type, NULL, node,
+ of_dev_node_match);
+ if (!dev)
+ return NULL;
+
+ return i2c_verify_client(dev);
+}
+EXPORT_SYMBOL(of_find_i2c_device_by_node);
+
+/* must call put_device() when done with returned i2c_adapter device */
+struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
+{
+ struct device *dev;
+
+ dev = bus_find_device(&i2c_bus_type, NULL, node,
+ of_dev_node_match);
+ if (!dev)
+ return NULL;
+
+ return i2c_verify_adapter(dev);
+}
+EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
+#else
+static void of_i2c_register_devices(struct i2c_adapter *adap) { }
+#endif /* CONFIG_OF */
+
+/* ACPI support code */
+
+#if IS_ENABLED(CONFIG_ACPI)
+static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
+{
+ struct i2c_board_info *info = data;
+
+ if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
+ struct acpi_resource_i2c_serialbus *sb;
+
+ sb = &ares->data.i2c_serial_bus;
+ if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
+ info->addr = sb->slave_address;
+ if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+ info->flags |= I2C_CLIENT_TEN;
+ }
+ } else if (info->irq < 0) {
+ struct resource r;
+
+ if (acpi_dev_resource_interrupt(ares, 0, &r))
+ info->irq = r.start;
+ }
+
+ /* Tell the ACPI core to skip this resource */
+ return 1;
+}
+
+static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
+ void *data, void **return_value)
+{
+ struct i2c_adapter *adapter = data;
+ struct list_head resource_list;
+ struct i2c_board_info info;
+ struct acpi_device *adev;
+ int ret;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+ if (acpi_bus_get_status(adev) || !adev->status.present)
+ return AE_OK;
+
+ memset(&info, 0, sizeof(info));
+ info.acpi_node.handle = handle;
+ info.irq = -1;
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ acpi_i2c_add_resource, &info);
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (ret < 0 || !info.addr)
+ return AE_OK;
+
+ strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
+ if (!i2c_new_device(adapter, &info)) {
+ dev_err(&adapter->dev,
+ "failed to add I2C device %s from ACPI\n",
+ dev_name(&adev->dev));
+ }
+
+ return AE_OK;
+}
+
+/**
+ * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
+ * @adap: pointer to adapter
+ *
+ * Enumerate all I2C slave devices behind this adapter by walking the ACPI
+ * namespace. When a device is found it will be added to the Linux device
+ * model and bound to the corresponding ACPI handle.
+ */
+static void acpi_i2c_register_devices(struct i2c_adapter *adap)
+{
+ acpi_handle handle;
+ acpi_status status;
+
+ handle = ACPI_HANDLE(adap->dev.parent);
+ if (!handle)
+ return;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ acpi_i2c_add_device, NULL,
+ adap, NULL);
+ if (ACPI_FAILURE(status))
+ dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
+}
+#else
+static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {}
+#endif /* CONFIG_ACPI */
+
static int i2c_do_add_adapter(struct i2c_driver *driver,
struct i2c_adapter *adap)
{
exit_recovery:
/* create pre-declared device nodes */
+ of_i2c_register_devices(adap);
+ acpi_i2c_register_devices(adap);
+
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
}
EXPORT_SYMBOL(i2c_del_adapter);
-
/* ------------------------------------------------------------------------- */
int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *))
err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
I2C_SMBUS_BYTE, &dummy);
else {
- dev_warn(&adap->dev, "No suitable probing method supported\n");
+ dev_warn(&adap->dev, "No suitable probing method supported for address 0x%02X\n",
+ addr);
err = -EOPNOTSUPP;
}
void i2c_put_adapter(struct i2c_adapter *adap)
{
- module_put(adap->owner);
+ if (adap)
+ module_put(adap->owner);
}
EXPORT_SYMBOL(i2c_put_adapter);
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/of.h>
-#include <linux/of_i2c.h>
/* multiplexer per channel data */
struct i2c_mux_priv {
dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
i2c_adapter_id(&priv->adap));
- of_i2c_register_devices(&priv->adap);
-
return &priv->adap;
}
EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
static int smbalert_probe(struct i2c_client *ara,
const struct i2c_device_id *id)
{
- struct i2c_smbus_alert_setup *setup = ara->dev.platform_data;
+ struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev);
struct i2c_smbus_alert *alert;
struct i2c_adapter *adapter = ara->adapter;
int res;
#include <linux/i2c-mux.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/of_i2c.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
dev_err(dev, "Cannot find device tree node\n");
return -ENODEV;
}
- if (dev->platform_data) {
+ if (dev_get_platdata(dev)) {
dev_err(dev, "Platform data is not supported\n");
return -EINVAL;
}
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/gpio.h>
-#include <linux/of_i2c.h>
#include <linux/of_gpio.h>
struct gpiomux {
platform_set_drvdata(pdev, mux);
- if (!pdev->dev.platform_data) {
+ if (!dev_get_platdata(&pdev->dev)) {
ret = i2c_mux_gpio_probe_dt(mux, pdev);
if (ret < 0)
return ret;
- } else
- memcpy(&mux->data, pdev->dev.platform_data, sizeof(mux->data));
+ } else {
+ memcpy(&mux->data, dev_get_platdata(&pdev->dev),
+ sizeof(mux->data));
+ }
/*
* If a GPIO chip name is provided, the GPIO pin numbers provided are
const struct i2c_device_id *id)
{
struct i2c_adapter *adap = client->adapter;
- struct pca954x_platform_data *pdata = client->dev.platform_data;
+ struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
struct pca9541 *data;
int force;
int ret = -ENODEV;
const struct i2c_device_id *id)
{
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
- struct pca954x_platform_data *pdata = client->dev.platform_data;
+ struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
int num, force, class;
struct pca954x *data;
int ret = -ENODEV;
#include <linux/i2c-mux.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/of_i2c.h>
#include <linux/pinctrl/consumer.h>
#include <linux/i2c-mux-pinctrl.h>
#include <linux/platform_device.h>
mux->dev = &pdev->dev;
- mux->pdata = pdev->dev.platform_data;
+ mux->pdata = dev_get_platdata(&pdev->dev);
if (!mux->pdata) {
ret = i2c_mux_pinctrl_parse_dt(mux, pdev);
if (ret < 0)
#include <linux/clk.h>
#include <linux/module.h>
-#include <linux/of_i2c.h>
+#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
pm_runtime_enable(&pdev->dev);
pm_runtime_enable(&i2c_adap->dev);
- of_i2c_register_devices(i2c_adap);
-
return 0;
}
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_i2c.h>
+#include <linux/i2c.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
-#include <linux/of_i2c.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/types.h>
def_bool y
depends on !SPARC
-config OF_I2C
- def_tristate I2C
- depends on I2C
- help
- OpenFirmware I2C accessors
-
config OF_NET
depends on NETDEVICES
def_bool y
obj-$(CONFIG_OF_PROMTREE) += pdt.o
obj-$(CONFIG_OF_ADDRESS) += address.o
obj-$(CONFIG_OF_IRQ) += irq.o
-obj-$(CONFIG_OF_I2C) += of_i2c.o
obj-$(CONFIG_OF_NET) += of_net.o
obj-$(CONFIG_OF_SELFTEST) += selftest.o
obj-$(CONFIG_OF_MDIO) += of_mdio.o
+++ /dev/null
-/*
- * OF helpers for the I2C API
- *
- * Copyright (c) 2008 Jochen Friedrich <jochen@scram.de>
- *
- * Based on a previous patch from Jon Smirl <jonsmirl@gmail.com>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/i2c.h>
-#include <linux/irq.h>
-#include <linux/of.h>
-#include <linux/of_i2c.h>
-#include <linux/of_irq.h>
-#include <linux/module.h>
-
-void of_i2c_register_devices(struct i2c_adapter *adap)
-{
- void *result;
- struct device_node *node;
-
- /* Only register child devices if the adapter has a node pointer set */
- if (!adap->dev.of_node)
- return;
-
- dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
-
- for_each_available_child_of_node(adap->dev.of_node, node) {
- struct i2c_board_info info = {};
- struct dev_archdata dev_ad = {};
- const __be32 *addr;
- int len;
-
- dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
-
- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
- dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
- node->full_name);
- continue;
- }
-
- addr = of_get_property(node, "reg", &len);
- if (!addr || (len < sizeof(int))) {
- dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
- node->full_name);
- continue;
- }
-
- info.addr = be32_to_cpup(addr);
- if (info.addr > (1 << 10) - 1) {
- dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
- info.addr, node->full_name);
- continue;
- }
-
- info.irq = irq_of_parse_and_map(node, 0);
- info.of_node = of_node_get(node);
- info.archdata = &dev_ad;
-
- if (of_get_property(node, "wakeup-source", NULL))
- info.flags |= I2C_CLIENT_WAKE;
-
- request_module("%s%s", I2C_MODULE_PREFIX, info.type);
-
- result = i2c_new_device(adap, &info);
- if (result == NULL) {
- dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
- node->full_name);
- of_node_put(node);
- irq_dispose_mapping(info.irq);
- continue;
- }
- }
-}
-EXPORT_SYMBOL(of_i2c_register_devices);
-
-static int of_dev_node_match(struct device *dev, void *data)
-{
- return dev->of_node == data;
-}
-
-/* must call put_device() when done with returned i2c_client device */
-struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
-{
- struct device *dev;
-
- dev = bus_find_device(&i2c_bus_type, NULL, node,
- of_dev_node_match);
- if (!dev)
- return NULL;
-
- return i2c_verify_client(dev);
-}
-EXPORT_SYMBOL(of_find_i2c_device_by_node);
-
-/* must call put_device() when done with returned i2c_adapter device */
-struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
-{
- struct device *dev;
-
- dev = bus_find_device(&i2c_bus_type, NULL, node,
- of_dev_node_match);
- if (!dev)
- return NULL;
-
- return i2c_verify_adapter(dev);
-}
-EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
-
-MODULE_LICENSE("GPL");
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
-#include <linux/of_i2c.h>
+#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/spinlock.h>
static inline struct i2c_adapter *
i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
{
+#if IS_ENABLED(I2C_MUX)
struct device *parent = adapter->dev.parent;
if (parent != NULL && parent->type == &i2c_adapter_type)
return to_i2c_adapter(parent);
else
+#endif
return NULL;
}
#endif /* I2C */
-#if IS_ENABLED(CONFIG_ACPI_I2C)
-extern void acpi_i2c_register_devices(struct i2c_adapter *adap);
+#if IS_ENABLED(CONFIG_OF)
+/* must call put_device() when done with returned i2c_client device */
+extern struct i2c_client *of_find_i2c_device_by_node(struct device_node *node);
+
+/* must call put_device() when done with returned i2c_adapter device */
+extern struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node);
+
#else
-static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {}
-#endif
+
+static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
+{
+ return NULL;
+}
+
+static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
+{
+ return NULL;
+}
+#endif /* CONFIG_OF */
#endif /* _LINUX_I2C_H */
unsigned int class;
unsigned int use_pio :1;
unsigned int fast_mode :1;
+ unsigned int high_mode:1;
+ unsigned char master_code;
+ unsigned long rate;
};
extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info);
+++ /dev/null
-/*
- * Generic I2C API implementation for PowerPC.
- *
- * Copyright (c) 2008 Jochen Friedrich <jochen@scram.de>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __LINUX_OF_I2C_H
-#define __LINUX_OF_I2C_H
-
-#if defined(CONFIG_OF_I2C) || defined(CONFIG_OF_I2C_MODULE)
-#include <linux/i2c.h>
-
-extern void of_i2c_register_devices(struct i2c_adapter *adap);
-
-/* must call put_device() when done with returned i2c_client device */
-extern struct i2c_client *of_find_i2c_device_by_node(struct device_node *node);
-
-/* must call put_device() when done with returned i2c_adapter device */
-extern struct i2c_adapter *of_find_i2c_adapter_by_node(
- struct device_node *node);
-
-#else
-static inline void of_i2c_register_devices(struct i2c_adapter *adap)
-{
- return;
-}
-
-static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
-{
- return NULL;
-}
-
-/* must call put_device() when done with returned i2c_adapter device */
-static inline struct i2c_adapter *of_find_i2c_adapter_by_node(
- struct device_node *node)
-{
- return NULL;
-}
-#endif /* CONFIG_OF_I2C */
-
-#endif /* __LINUX_OF_I2C_H */
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
-#include <linux/of_i2c.h>
+#include <linux/i2c.h>
#include <linux/clk.h>
#include <sound/soc.h>
#include <linux/module.h>
#include <linux/of_platform.h>
-#include <linux/of_i2c.h>
+#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <sound/soc.h>