mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
Merge branch 'for-linus/2639/i2c-2' of git://git.fluff.org/bjdooks/linux
* 'for-linus/2639/i2c-2' of git://git.fluff.org/bjdooks/linux: i2c-pxa2xx: Don't clear isr bits too early i2c-pxa2xx: Fix register offsets i2c-pxa2xx: pass of_node from platform driver to adapter and publish i2c-pxa2xx: check timeout correctly i2c-pxa2xx: add support for shared IRQ handler i2c-pxa2xx: Add PCI support for PXA I2C controller ARM: pxa2xx: reorganize I2C files i2c-pxa2xx: use dynamic register layout i2c-mxs: set controller to pio queue mode after reset i2c-eg20t: support new device OKI SEMICONDUCTOR ML7213 IOH i2c/busses: Add support for Diolan U2C-12 USB-I2C adapter
This commit is contained in:
commit
75ea6358bc
26
Documentation/i2c/busses/i2c-diolan-u2c
Normal file
26
Documentation/i2c/busses/i2c-diolan-u2c
Normal file
@ -0,0 +1,26 @@
|
||||
Kernel driver i2c-diolan-u2c
|
||||
|
||||
Supported adapters:
|
||||
* Diolan U2C-12 I2C-USB adapter
|
||||
Documentation:
|
||||
http://www.diolan.com/i2c/u2c12.html
|
||||
|
||||
Author: Guenter Roeck <guenter.roeck@ericsson.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This is the driver for the Diolan U2C-12 USB-I2C adapter.
|
||||
|
||||
The Diolan U2C-12 I2C-USB Adapter provides a low cost solution to connect
|
||||
a computer to I2C slave devices using a USB interface. It also supports
|
||||
connectivity to SPI devices.
|
||||
|
||||
This driver only supports the I2C interface of U2C-12. The driver does not use
|
||||
interrupts.
|
||||
|
||||
|
||||
Module parameters
|
||||
-----------------
|
||||
|
||||
* frequency: I2C bus frequency
|
@ -2138,6 +2138,12 @@ F: Documentation/serial/digiepca.txt
|
||||
F: drivers/char/epca*
|
||||
F: drivers/char/digi*
|
||||
|
||||
DIOLAN U2C-12 I2C DRIVER
|
||||
M: Guenter Roeck <guenter.roeck@ericsson.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/i2c/busses/i2c-diolan-u2c.c
|
||||
|
||||
DIRECTORY NOTIFICATION (DNOTIFY)
|
||||
M: Eric Paris <eparis@parisplace.org>
|
||||
S: Maintained
|
||||
|
@ -11,8 +11,8 @@ extern void __init mmp2_init_irq(void);
|
||||
extern void mmp2_clear_pmic_int(void);
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <mach/devices.h>
|
||||
#include <plat/i2c.h>
|
||||
|
||||
extern struct pxa_device_desc mmp2_device_uart1;
|
||||
extern struct pxa_device_desc mmp2_device_uart2;
|
||||
|
@ -8,8 +8,8 @@ extern void __init pxa168_init_irq(void);
|
||||
extern void pxa168_clear_keypad_wakeup(void);
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <mach/devices.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <plat/pxa3xx_nand.h>
|
||||
#include <video/pxa168fb.h>
|
||||
#include <plat/pxa27x_keypad.h>
|
||||
|
@ -7,8 +7,8 @@ extern struct sys_timer pxa910_timer;
|
||||
extern void __init pxa910_init_irq(void);
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <mach/devices.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <plat/pxa3xx_nand.h>
|
||||
|
||||
extern struct pxa_device_desc pxa910_device_uart1;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c/pcf857x.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/regulator/max1586.h>
|
||||
@ -51,8 +52,6 @@
|
||||
#include <mach/irda.h>
|
||||
#include <mach/ohci.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "generic.h"
|
||||
#include "devices.h"
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pca953x.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <linux/mfd/da903x.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
@ -48,7 +49,6 @@
|
||||
#include <mach/pxafb.h>
|
||||
#include <mach/mmc.h>
|
||||
#include <mach/ohci.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <plat/pxa3xx_nand.h>
|
||||
#include <mach/audio.h>
|
||||
#include <mach/pxa3xx-u2d.h>
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <mach/pxa27x.h>
|
||||
#include <mach/colibri.h>
|
||||
@ -27,8 +28,6 @@
|
||||
#include <mach/ohci.h>
|
||||
#include <mach/pxa27x-udc.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "generic.h"
|
||||
#include "devices.h"
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/sysdev.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
@ -33,8 +34,6 @@
|
||||
#include <mach/pxa27x-udc.h>
|
||||
#include <mach/pxafb.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "devices.h"
|
||||
#include "generic.h"
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/ads7846.h>
|
||||
@ -45,7 +46,6 @@
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
#include <mach/pxa25x.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/irda.h>
|
||||
#include <mach/mmc.h>
|
||||
#include <mach/udc.h>
|
||||
|
@ -17,12 +17,12 @@
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/sm501.h>
|
||||
#include <linux/smsc911x.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <mach/csb726.h>
|
||||
#include <mach/mfp-pxa27x.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/mmc.h>
|
||||
#include <mach/ohci.h>
|
||||
#include <mach/pxa2xx-regs.h>
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/pmu.h>
|
||||
#include <mach/udc.h>
|
||||
@ -16,7 +17,6 @@
|
||||
#include <mach/camera.h>
|
||||
#include <mach/audio.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <plat/pxa3xx_nand.h>
|
||||
|
||||
#include "devices.h"
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <linux/apm-emulation.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pca953x.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/regulator/userspace-consumer.h>
|
||||
|
||||
#include <media/soc_camera.h>
|
||||
@ -45,7 +46,6 @@
|
||||
#include <mach/ohci.h>
|
||||
#include <mach/mmc.h>
|
||||
#include <plat/pxa27x_keypad.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/camera.h>
|
||||
|
||||
#include "generic.h"
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/leds-lp3944.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <media/soc_camera.h>
|
||||
|
||||
@ -30,7 +31,6 @@
|
||||
#include <mach/pxa27x.h>
|
||||
#include <mach/pxafb.h>
|
||||
#include <mach/ohci.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <plat/pxa27x_keypad.h>
|
||||
#include <mach/camera.h>
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
#include <linux/usb/gpio_vbus.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/mach-types.h>
|
||||
@ -42,7 +43,6 @@
|
||||
|
||||
#include <mach/pxa27x.h>
|
||||
#include <mach/hx4700.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/irda.h>
|
||||
|
||||
#include <video/platform_lcd.h>
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/leds.h>
|
||||
#include <linux/mfd/da903x.h>
|
||||
#include <linux/i2c/max732x.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <asm/setup.h>
|
||||
@ -45,7 +46,6 @@
|
||||
#include <mach/mmc.h>
|
||||
#include <plat/pxa27x_keypad.h>
|
||||
#include <mach/littleton.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <plat/pxa3xx_nand.h>
|
||||
|
||||
#include "generic.h"
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/regulator/bq24022.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/usb/gpio_vbus.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/mach-types.h>
|
||||
@ -36,7 +37,6 @@
|
||||
#include <mach/pxa27x.h>
|
||||
#include <mach/magician.h>
|
||||
#include <mach/pxafb.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/mmc.h>
|
||||
#include <mach/irda.h>
|
||||
#include <mach/ohci.h>
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
#include <linux/smc91x.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <asm/setup.h>
|
||||
@ -46,7 +47,6 @@
|
||||
#include <mach/mainstone.h>
|
||||
#include <mach/audio.h>
|
||||
#include <mach/pxafb.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/mmc.h>
|
||||
#include <mach/irda.h>
|
||||
#include <mach/ohci.h>
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <linux/usb/gpio_vbus.h>
|
||||
#include <linux/regulator/max1586.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
@ -50,7 +51,6 @@
|
||||
#include <mach/mmc.h>
|
||||
#include <mach/udc.h>
|
||||
#include <mach/pxa27x-udc.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/camera.h>
|
||||
#include <mach/audio.h>
|
||||
#include <media/soc_camera.h>
|
||||
|
@ -22,8 +22,8 @@
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/dm9000.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
#include <plat/pxa3xx_nand.h>
|
||||
|
||||
#include <mach/pxafb.h>
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/usb/gpio_vbus.h>
|
||||
#include <linux/regulator/max1586.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
@ -36,8 +37,6 @@
|
||||
#include <mach/palmasoc.h>
|
||||
#include <mach/palm27x.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "generic.h"
|
||||
#include "devices.h"
|
||||
|
||||
|
@ -23,12 +23,12 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
|
||||
#include <media/soc_camera.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/camera.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <mach/pxa27x.h>
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/ads7846.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
@ -44,7 +45,6 @@
|
||||
#include <mach/irda.h>
|
||||
#include <mach/poodle.h>
|
||||
#include <mach/pxafb.h>
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include <asm/hardware/scoop.h>
|
||||
#include <asm/hardware/locomo.h>
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/sysdev.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/mach/map.h>
|
||||
#include <mach/hardware.h>
|
||||
@ -32,8 +33,6 @@
|
||||
#include <mach/dma.h>
|
||||
#include <mach/smemc.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "generic.h"
|
||||
#include "devices.h"
|
||||
#include "clock.h"
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/sysdev.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/mach/map.h>
|
||||
#include <mach/hardware.h>
|
||||
@ -32,7 +33,6 @@
|
||||
#include <mach/dma.h>
|
||||
#include <mach/regs-intc.h>
|
||||
#include <mach/smemc.h>
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "generic.h"
|
||||
#include "devices.h"
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/sysdev.h>
|
||||
@ -27,7 +28,6 @@
|
||||
#include <mach/pm.h>
|
||||
#include <mach/dma.h>
|
||||
#include <mach/regs-intc.h>
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "generic.h"
|
||||
#include "devices.h"
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi_gpio.h>
|
||||
#include <linux/lis3lv02d.h>
|
||||
@ -53,7 +54,6 @@
|
||||
#include <mach/ohci.h>
|
||||
#include <mach/pxafb.h>
|
||||
#include <mach/mmc.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <plat/pxa3xx_nand.h>
|
||||
|
||||
#include "generic.h"
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/smc91x.h>
|
||||
#include <linux/mfd/da903x.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
@ -31,7 +32,6 @@
|
||||
#include <asm/mach/flash.h>
|
||||
|
||||
#include <mach/pxa930.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/pxafb.h>
|
||||
|
||||
#include "devices.h"
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
@ -24,8 +25,6 @@
|
||||
#include <mach/mfp-pxa930.h>
|
||||
#include <mach/gpio.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "generic.h"
|
||||
|
||||
#define SAARB_NR_IRQS (IRQ_BOARD_START + 40)
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/i2c/pca953x.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/ads7846.h>
|
||||
@ -47,8 +48,6 @@
|
||||
#include <mach/sharpsl_pm.h>
|
||||
#include <mach/smemc.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "generic.h"
|
||||
#include "devices.h"
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/mtd/plat-ram.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/i2c/pcf857x.h>
|
||||
#include <linux/i2c/at24.h>
|
||||
#include <linux/smc91x.h>
|
||||
@ -43,7 +44,6 @@
|
||||
#include <asm/mach/flash.h>
|
||||
|
||||
#include <mach/pxa27x.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/mmc.h>
|
||||
#include <mach/udc.h>
|
||||
#include <mach/pxa27x-udc.h>
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
|
||||
@ -23,8 +24,6 @@
|
||||
|
||||
#include <mach/pxa930.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "devices.h"
|
||||
#include "generic.h"
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/mach-types.h>
|
||||
@ -41,7 +42,6 @@
|
||||
#include <mach/pxa25x.h>
|
||||
#include <mach/reset.h>
|
||||
#include <mach/irda.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/mmc.h>
|
||||
#include <mach/udc.h>
|
||||
#include <mach/tosa_bt.h>
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/dm9000.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <asm/setup.h>
|
||||
@ -47,7 +48,6 @@
|
||||
#include <mach/irda.h>
|
||||
#include <mach/ohci.h>
|
||||
#include <mach/smemc.h>
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "generic.h"
|
||||
#include "devices.h"
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/smc91x.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
@ -47,7 +48,6 @@
|
||||
#include <mach/pxa25x.h>
|
||||
#include <mach/audio.h>
|
||||
#include <mach/pxafb.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/regs-uart.h>
|
||||
#include <mach/arcom-pcmcia.h>
|
||||
#include <mach/viper.h>
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/ucb1400.h>
|
||||
#include <linux/ata_platform.h>
|
||||
#include <linux/regulator/max1586.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
@ -40,8 +41,6 @@
|
||||
#include <mach/udc.h>
|
||||
#include <mach/pata_pxa.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "generic.h"
|
||||
#include "devices.h"
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/smc91x.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
@ -26,8 +27,6 @@
|
||||
#include <asm/mach/irq.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/pxa2xx-regs.h>
|
||||
#include <mach/mfp-pxa25x.h>
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
@ -40,8 +41,6 @@
|
||||
#include <mach/mmc.h>
|
||||
#include <plat/pxa27x_keypad.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include "generic.h"
|
||||
#include "devices.h"
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/i2c/pca953x.h>
|
||||
#include <linux/apm-emulation.h>
|
||||
#include <linux/can/platform/mcp251x.h>
|
||||
@ -33,8 +34,6 @@
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#include <mach/pxa2xx-regs.h>
|
||||
#include <mach/regs-uart.h>
|
||||
#include <mach/ohci.h>
|
||||
|
@ -17,11 +17,11 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/i2c/pca953x.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/pxa300.h>
|
||||
#include <plat/i2c.h>
|
||||
#include <mach/zylonite.h>
|
||||
|
||||
#include "generic.h"
|
||||
|
@ -547,15 +547,18 @@ config I2C_PUV3
|
||||
|
||||
config I2C_PXA
|
||||
tristate "Intel PXA2XX I2C adapter"
|
||||
depends on ARCH_PXA || ARCH_MMP
|
||||
depends on ARCH_PXA || ARCH_MMP || (X86_32 && PCI && OF)
|
||||
help
|
||||
If you have devices in the PXA I2C bus, say yes to this option.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-pxa.
|
||||
|
||||
config I2C_PXA_PCI
|
||||
def_bool I2C_PXA && X86_32 && PCI && OF
|
||||
|
||||
config I2C_PXA_SLAVE
|
||||
bool "Intel PXA2XX I2C Slave comms support"
|
||||
depends on I2C_PXA
|
||||
depends on I2C_PXA && !X86_32
|
||||
help
|
||||
Support I2C slave mode communications on the PXA I2C bus. This
|
||||
is necessary for systems where the PXA may be a target on the
|
||||
@ -668,15 +671,28 @@ config I2C_XILINX
|
||||
will be called xilinx_i2c.
|
||||
|
||||
config I2C_EG20T
|
||||
tristate "PCH I2C of Intel EG20T"
|
||||
depends on PCI
|
||||
help
|
||||
This driver is for PCH(Platform controller Hub) I2C of EG20T which
|
||||
is an IOH(Input/Output Hub) for x86 embedded processor.
|
||||
This driver can access PCH I2C bus device.
|
||||
tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH"
|
||||
depends on PCI
|
||||
help
|
||||
This driver is for PCH(Platform controller Hub) I2C of EG20T which
|
||||
is an IOH(Input/Output Hub) for x86 embedded processor.
|
||||
This driver can access PCH I2C bus device.
|
||||
|
||||
This driver also supports the ML7213, a companion chip for the
|
||||
Atom E6xx series and compatible with the Intel EG20T PCH.
|
||||
|
||||
comment "External I2C/SMBus adapter drivers"
|
||||
|
||||
config I2C_DIOLAN_U2C
|
||||
tristate "Diolan U2C-12 USB adapter"
|
||||
depends on USB
|
||||
help
|
||||
If you say yes to this option, support will be included for Diolan
|
||||
U2C-12, a USB to I2C interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-diolan-u2c.
|
||||
|
||||
config I2C_PARPORT
|
||||
tristate "Parallel port adapter"
|
||||
depends on PARPORT
|
||||
|
@ -54,6 +54,7 @@ obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
|
||||
obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
|
||||
obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
|
||||
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
|
||||
obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
|
||||
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
|
||||
obj-$(CONFIG_I2C_S6000) += i2c-s6000.o
|
||||
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
|
||||
@ -67,6 +68,7 @@ obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
|
||||
obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
|
||||
|
||||
# External I2C/SMBus adapter drivers
|
||||
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
|
||||
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
|
||||
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
|
||||
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
|
||||
|
535
drivers/i2c/busses/i2c-diolan-u2c.c
Normal file
535
drivers/i2c/busses/i2c-diolan-u2c.c
Normal file
@ -0,0 +1,535 @@
|
||||
/*
|
||||
* Driver for the Diolan u2c-12 USB-I2C adapter
|
||||
*
|
||||
* Copyright (c) 2010-2011 Ericsson AB
|
||||
*
|
||||
* Derived from:
|
||||
* i2c-tiny-usb.c
|
||||
* Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#define DRIVER_NAME "i2c-diolan-u2c"
|
||||
|
||||
#define USB_VENDOR_ID_DIOLAN 0x0abf
|
||||
#define USB_DEVICE_ID_DIOLAN_U2C 0x3370
|
||||
|
||||
#define DIOLAN_OUT_EP 0x02
|
||||
#define DIOLAN_IN_EP 0x84
|
||||
|
||||
/* commands via USB, must match command ids in the firmware */
|
||||
#define CMD_I2C_READ 0x01
|
||||
#define CMD_I2C_WRITE 0x02
|
||||
#define CMD_I2C_SCAN 0x03 /* Returns list of detected devices */
|
||||
#define CMD_I2C_RELEASE_SDA 0x04
|
||||
#define CMD_I2C_RELEASE_SCL 0x05
|
||||
#define CMD_I2C_DROP_SDA 0x06
|
||||
#define CMD_I2C_DROP_SCL 0x07
|
||||
#define CMD_I2C_READ_SDA 0x08
|
||||
#define CMD_I2C_READ_SCL 0x09
|
||||
#define CMD_GET_FW_VERSION 0x0a
|
||||
#define CMD_GET_SERIAL 0x0b
|
||||
#define CMD_I2C_START 0x0c
|
||||
#define CMD_I2C_STOP 0x0d
|
||||
#define CMD_I2C_REPEATED_START 0x0e
|
||||
#define CMD_I2C_PUT_BYTE 0x0f
|
||||
#define CMD_I2C_GET_BYTE 0x10
|
||||
#define CMD_I2C_PUT_ACK 0x11
|
||||
#define CMD_I2C_GET_ACK 0x12
|
||||
#define CMD_I2C_PUT_BYTE_ACK 0x13
|
||||
#define CMD_I2C_GET_BYTE_ACK 0x14
|
||||
#define CMD_I2C_SET_SPEED 0x1b
|
||||
#define CMD_I2C_GET_SPEED 0x1c
|
||||
#define CMD_I2C_SET_CLK_SYNC 0x24
|
||||
#define CMD_I2C_GET_CLK_SYNC 0x25
|
||||
#define CMD_I2C_SET_CLK_SYNC_TO 0x26
|
||||
#define CMD_I2C_GET_CLK_SYNC_TO 0x27
|
||||
|
||||
#define RESP_OK 0x00
|
||||
#define RESP_FAILED 0x01
|
||||
#define RESP_BAD_MEMADDR 0x04
|
||||
#define RESP_DATA_ERR 0x05
|
||||
#define RESP_NOT_IMPLEMENTED 0x06
|
||||
#define RESP_NACK 0x07
|
||||
#define RESP_TIMEOUT 0x09
|
||||
|
||||
#define U2C_I2C_SPEED_FAST 0 /* 400 kHz */
|
||||
#define U2C_I2C_SPEED_STD 1 /* 100 kHz */
|
||||
#define U2C_I2C_SPEED_2KHZ 242 /* 2 kHz, minimum speed */
|
||||
#define U2C_I2C_SPEED(f) ((DIV_ROUND_UP(1000000, (f)) - 10) / 2 + 1)
|
||||
|
||||
#define U2C_I2C_FREQ_FAST 400000
|
||||
#define U2C_I2C_FREQ_STD 100000
|
||||
#define U2C_I2C_FREQ(s) (1000000 / (2 * (s - 1) + 10))
|
||||
|
||||
#define DIOLAN_USB_TIMEOUT 100 /* in ms */
|
||||
#define DIOLAN_SYNC_TIMEOUT 20 /* in ms */
|
||||
|
||||
#define DIOLAN_OUTBUF_LEN 128
|
||||
#define DIOLAN_FLUSH_LEN (DIOLAN_OUTBUF_LEN - 4)
|
||||
#define DIOLAN_INBUF_LEN 256 /* Maximum supported receive length */
|
||||
|
||||
/* Structure to hold all of our device specific stuff */
|
||||
struct i2c_diolan_u2c {
|
||||
u8 obuffer[DIOLAN_OUTBUF_LEN]; /* output buffer */
|
||||
u8 ibuffer[DIOLAN_INBUF_LEN]; /* input buffer */
|
||||
struct usb_device *usb_dev; /* the usb device for this device */
|
||||
struct usb_interface *interface;/* the interface for this device */
|
||||
struct i2c_adapter adapter; /* i2c related things */
|
||||
int olen; /* Output buffer length */
|
||||
int ocount; /* Number of enqueued messages */
|
||||
};
|
||||
|
||||
static uint frequency = U2C_I2C_FREQ_STD; /* I2C clock frequency in Hz */
|
||||
|
||||
module_param(frequency, uint, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(frequency, "I2C clock frequency in hertz");
|
||||
|
||||
/* usb layer */
|
||||
|
||||
/* Send command to device, and get response. */
|
||||
static int diolan_usb_transfer(struct i2c_diolan_u2c *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
int actual;
|
||||
int i;
|
||||
|
||||
if (!dev->olen || !dev->ocount)
|
||||
return -EINVAL;
|
||||
|
||||
ret = usb_bulk_msg(dev->usb_dev,
|
||||
usb_sndbulkpipe(dev->usb_dev, DIOLAN_OUT_EP),
|
||||
dev->obuffer, dev->olen, &actual,
|
||||
DIOLAN_USB_TIMEOUT);
|
||||
if (!ret) {
|
||||
for (i = 0; i < dev->ocount; i++) {
|
||||
int tmpret;
|
||||
|
||||
tmpret = usb_bulk_msg(dev->usb_dev,
|
||||
usb_rcvbulkpipe(dev->usb_dev,
|
||||
DIOLAN_IN_EP),
|
||||
dev->ibuffer,
|
||||
sizeof(dev->ibuffer), &actual,
|
||||
DIOLAN_USB_TIMEOUT);
|
||||
/*
|
||||
* Stop command processing if a previous command
|
||||
* returned an error.
|
||||
* Note that we still need to retrieve all messages.
|
||||
*/
|
||||
if (ret < 0)
|
||||
continue;
|
||||
ret = tmpret;
|
||||
if (ret == 0 && actual > 0) {
|
||||
switch (dev->ibuffer[actual - 1]) {
|
||||
case RESP_NACK:
|
||||
/*
|
||||
* Return ENXIO if NACK was received as
|
||||
* response to the address phase,
|
||||
* EIO otherwise
|
||||
*/
|
||||
ret = i == 1 ? -ENXIO : -EIO;
|
||||
break;
|
||||
case RESP_TIMEOUT:
|
||||
ret = -ETIMEDOUT;
|
||||
break;
|
||||
case RESP_OK:
|
||||
/* strip off return code */
|
||||
ret = actual - 1;
|
||||
break;
|
||||
default:
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dev->olen = 0;
|
||||
dev->ocount = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int diolan_write_cmd(struct i2c_diolan_u2c *dev, bool flush)
|
||||
{
|
||||
if (flush || dev->olen >= DIOLAN_FLUSH_LEN)
|
||||
return diolan_usb_transfer(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send command (no data) */
|
||||
static int diolan_usb_cmd(struct i2c_diolan_u2c *dev, u8 command, bool flush)
|
||||
{
|
||||
dev->obuffer[dev->olen++] = command;
|
||||
dev->ocount++;
|
||||
return diolan_write_cmd(dev, flush);
|
||||
}
|
||||
|
||||
/* Send command with one byte of data */
|
||||
static int diolan_usb_cmd_data(struct i2c_diolan_u2c *dev, u8 command, u8 data,
|
||||
bool flush)
|
||||
{
|
||||
dev->obuffer[dev->olen++] = command;
|
||||
dev->obuffer[dev->olen++] = data;
|
||||
dev->ocount++;
|
||||
return diolan_write_cmd(dev, flush);
|
||||
}
|
||||
|
||||
/* Send command with two bytes of data */
|
||||
static int diolan_usb_cmd_data2(struct i2c_diolan_u2c *dev, u8 command, u8 d1,
|
||||
u8 d2, bool flush)
|
||||
{
|
||||
dev->obuffer[dev->olen++] = command;
|
||||
dev->obuffer[dev->olen++] = d1;
|
||||
dev->obuffer[dev->olen++] = d2;
|
||||
dev->ocount++;
|
||||
return diolan_write_cmd(dev, flush);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush input queue.
|
||||
* If we don't do this at startup and the controller has queued up
|
||||
* messages which were not retrieved, it will stop responding
|
||||
* at some point.
|
||||
*/
|
||||
static void diolan_flush_input(struct i2c_diolan_u2c *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
int actual = 0;
|
||||
int ret;
|
||||
|
||||
ret = usb_bulk_msg(dev->usb_dev,
|
||||
usb_rcvbulkpipe(dev->usb_dev, DIOLAN_IN_EP),
|
||||
dev->ibuffer, sizeof(dev->ibuffer), &actual,
|
||||
DIOLAN_USB_TIMEOUT);
|
||||
if (ret < 0 || actual == 0)
|
||||
break;
|
||||
}
|
||||
if (i == 10)
|
||||
dev_err(&dev->interface->dev, "Failed to flush input buffer\n");
|
||||
}
|
||||
|
||||
static int diolan_i2c_start(struct i2c_diolan_u2c *dev)
|
||||
{
|
||||
return diolan_usb_cmd(dev, CMD_I2C_START, false);
|
||||
}
|
||||
|
||||
static int diolan_i2c_repeated_start(struct i2c_diolan_u2c *dev)
|
||||
{
|
||||
return diolan_usb_cmd(dev, CMD_I2C_REPEATED_START, false);
|
||||
}
|
||||
|
||||
static int diolan_i2c_stop(struct i2c_diolan_u2c *dev)
|
||||
{
|
||||
return diolan_usb_cmd(dev, CMD_I2C_STOP, true);
|
||||
}
|
||||
|
||||
static int diolan_i2c_get_byte_ack(struct i2c_diolan_u2c *dev, bool ack,
|
||||
u8 *byte)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = diolan_usb_cmd_data(dev, CMD_I2C_GET_BYTE_ACK, ack, true);
|
||||
if (ret > 0)
|
||||
*byte = dev->ibuffer[0];
|
||||
else if (ret == 0)
|
||||
ret = -EIO;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int diolan_i2c_put_byte_ack(struct i2c_diolan_u2c *dev, u8 byte)
|
||||
{
|
||||
return diolan_usb_cmd_data(dev, CMD_I2C_PUT_BYTE_ACK, byte, false);
|
||||
}
|
||||
|
||||
static int diolan_set_speed(struct i2c_diolan_u2c *dev, u8 speed)
|
||||
{
|
||||
return diolan_usb_cmd_data(dev, CMD_I2C_SET_SPEED, speed, true);
|
||||
}
|
||||
|
||||
/* Enable or disable clock synchronization (stretching) */
|
||||
static int diolan_set_clock_synch(struct i2c_diolan_u2c *dev, bool enable)
|
||||
{
|
||||
return diolan_usb_cmd_data(dev, CMD_I2C_SET_CLK_SYNC, enable, true);
|
||||
}
|
||||
|
||||
/* Set clock synchronization timeout in ms */
|
||||
static int diolan_set_clock_synch_timeout(struct i2c_diolan_u2c *dev, int ms)
|
||||
{
|
||||
int to_val = ms * 10;
|
||||
|
||||
return diolan_usb_cmd_data2(dev, CMD_I2C_SET_CLK_SYNC_TO,
|
||||
to_val & 0xff, (to_val >> 8) & 0xff, true);
|
||||
}
|
||||
|
||||
static void diolan_fw_version(struct i2c_diolan_u2c *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = diolan_usb_cmd(dev, CMD_GET_FW_VERSION, true);
|
||||
if (ret >= 2)
|
||||
dev_info(&dev->interface->dev,
|
||||
"Diolan U2C firmware version %u.%u\n",
|
||||
(unsigned int)dev->ibuffer[0],
|
||||
(unsigned int)dev->ibuffer[1]);
|
||||
}
|
||||
|
||||
static void diolan_get_serial(struct i2c_diolan_u2c *dev)
|
||||
{
|
||||
int ret;
|
||||
u32 serial;
|
||||
|
||||
ret = diolan_usb_cmd(dev, CMD_GET_SERIAL, true);
|
||||
if (ret >= 4) {
|
||||
serial = le32_to_cpu(*(u32 *)dev->ibuffer);
|
||||
dev_info(&dev->interface->dev,
|
||||
"Diolan U2C serial number %u\n", serial);
|
||||
}
|
||||
}
|
||||
|
||||
static int diolan_init(struct i2c_diolan_u2c *dev)
|
||||
{
|
||||
int speed, ret;
|
||||
|
||||
if (frequency >= 200000) {
|
||||
speed = U2C_I2C_SPEED_FAST;
|
||||
frequency = U2C_I2C_FREQ_FAST;
|
||||
} else if (frequency >= 100000 || frequency == 0) {
|
||||
speed = U2C_I2C_SPEED_STD;
|
||||
frequency = U2C_I2C_FREQ_STD;
|
||||
} else {
|
||||
speed = U2C_I2C_SPEED(frequency);
|
||||
if (speed > U2C_I2C_SPEED_2KHZ)
|
||||
speed = U2C_I2C_SPEED_2KHZ;
|
||||
frequency = U2C_I2C_FREQ(speed);
|
||||
}
|
||||
|
||||
dev_info(&dev->interface->dev,
|
||||
"Diolan U2C at USB bus %03d address %03d speed %d Hz\n",
|
||||
dev->usb_dev->bus->busnum, dev->usb_dev->devnum, frequency);
|
||||
|
||||
diolan_flush_input(dev);
|
||||
diolan_fw_version(dev);
|
||||
diolan_get_serial(dev);
|
||||
|
||||
/* Set I2C speed */
|
||||
ret = diolan_set_speed(dev, speed);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure I2C clock synchronization */
|
||||
ret = diolan_set_clock_synch(dev, speed != U2C_I2C_SPEED_FAST);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (speed != U2C_I2C_SPEED_FAST)
|
||||
ret = diolan_set_clock_synch_timeout(dev, DIOLAN_SYNC_TIMEOUT);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* i2c layer */
|
||||
|
||||
static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct i2c_diolan_u2c *dev = i2c_get_adapdata(adapter);
|
||||
struct i2c_msg *pmsg;
|
||||
int i, j;
|
||||
int ret, sret;
|
||||
|
||||
ret = diolan_i2c_start(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
pmsg = &msgs[i];
|
||||
if (i) {
|
||||
ret = diolan_i2c_repeated_start(dev);
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
}
|
||||
if (pmsg->flags & I2C_M_RD) {
|
||||
ret =
|
||||
diolan_i2c_put_byte_ack(dev, (pmsg->addr << 1) | 1);
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
for (j = 0; j < pmsg->len; j++) {
|
||||
u8 byte;
|
||||
bool ack = j < pmsg->len - 1;
|
||||
|
||||
/*
|
||||
* Don't send NACK if this is the first byte
|
||||
* of a SMBUS_BLOCK message.
|
||||
*/
|
||||
if (j == 0 && (pmsg->flags & I2C_M_RECV_LEN))
|
||||
ack = true;
|
||||
|
||||
ret = diolan_i2c_get_byte_ack(dev, ack, &byte);
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
/*
|
||||
* Adjust count if first received byte is length
|
||||
*/
|
||||
if (j == 0 && (pmsg->flags & I2C_M_RECV_LEN)) {
|
||||
if (byte == 0
|
||||
|| byte > I2C_SMBUS_BLOCK_MAX) {
|
||||
ret = -EPROTO;
|
||||
goto abort;
|
||||
}
|
||||
pmsg->len += byte;
|
||||
}
|
||||
pmsg->buf[j] = byte;
|
||||
}
|
||||
} else {
|
||||
ret = diolan_i2c_put_byte_ack(dev, pmsg->addr << 1);
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
for (j = 0; j < pmsg->len; j++) {
|
||||
ret = diolan_i2c_put_byte_ack(dev,
|
||||
pmsg->buf[j]);
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
}
|
||||
abort:
|
||||
sret = diolan_i2c_stop(dev);
|
||||
if (sret < 0 && ret >= 0)
|
||||
ret = sret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return list of supported functionality.
|
||||
*/
|
||||
static u32 diolan_usb_func(struct i2c_adapter *a)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
|
||||
I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm diolan_usb_algorithm = {
|
||||
.master_xfer = diolan_usb_xfer,
|
||||
.functionality = diolan_usb_func,
|
||||
};
|
||||
|
||||
/* device layer */
|
||||
|
||||
static const struct usb_device_id diolan_u2c_table[] = {
|
||||
{ USB_DEVICE(USB_VENDOR_ID_DIOLAN, USB_DEVICE_ID_DIOLAN_U2C) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, diolan_u2c_table);
|
||||
|
||||
static void diolan_u2c_free(struct i2c_diolan_u2c *dev)
|
||||
{
|
||||
usb_put_dev(dev->usb_dev);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static int diolan_u2c_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct i2c_diolan_u2c *dev;
|
||||
int ret;
|
||||
|
||||
/* allocate memory for our device state and initialize it */
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (dev == NULL) {
|
||||
dev_err(&interface->dev, "no memory for device state\n");
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
|
||||
dev->interface = interface;
|
||||
|
||||
/* save our data pointer in this interface device */
|
||||
usb_set_intfdata(interface, dev);
|
||||
|
||||
/* setup i2c adapter description */
|
||||
dev->adapter.owner = THIS_MODULE;
|
||||
dev->adapter.class = I2C_CLASS_HWMON;
|
||||
dev->adapter.algo = &diolan_usb_algorithm;
|
||||
i2c_set_adapdata(&dev->adapter, dev);
|
||||
snprintf(dev->adapter.name, sizeof(dev->adapter.name),
|
||||
DRIVER_NAME " at bus %03d device %03d",
|
||||
dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
|
||||
|
||||
dev->adapter.dev.parent = &dev->interface->dev;
|
||||
|
||||
/* initialize diolan i2c interface */
|
||||
ret = diolan_init(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&interface->dev, "failed to initialize adapter\n");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
/* and finally attach to i2c layer */
|
||||
ret = i2c_add_adapter(&dev->adapter);
|
||||
if (ret < 0) {
|
||||
dev_err(&interface->dev, "failed to add I2C adapter\n");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
dev_dbg(&interface->dev, "connected " DRIVER_NAME "\n");
|
||||
|
||||
return 0;
|
||||
|
||||
error_free:
|
||||
usb_set_intfdata(interface, NULL);
|
||||
diolan_u2c_free(dev);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void diolan_u2c_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct i2c_diolan_u2c *dev = usb_get_intfdata(interface);
|
||||
|
||||
i2c_del_adapter(&dev->adapter);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
diolan_u2c_free(dev);
|
||||
|
||||
dev_dbg(&interface->dev, "disconnected\n");
|
||||
}
|
||||
|
||||
static struct usb_driver diolan_u2c_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe = diolan_u2c_probe,
|
||||
.disconnect = diolan_u2c_disconnect,
|
||||
.id_table = diolan_u2c_table,
|
||||
};
|
||||
|
||||
static int __init diolan_u2c_init(void)
|
||||
{
|
||||
/* register this driver with the USB subsystem */
|
||||
return usb_register(&diolan_u2c_driver);
|
||||
}
|
||||
|
||||
static void __exit diolan_u2c_exit(void)
|
||||
{
|
||||
/* deregister this driver with the USB subsystem */
|
||||
usb_deregister(&diolan_u2c_driver);
|
||||
}
|
||||
|
||||
module_init(diolan_u2c_init);
|
||||
module_exit(diolan_u2c_exit);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
|
||||
MODULE_DESCRIPTION(DRIVER_NAME " driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -132,6 +132,13 @@
|
||||
#define pch_pci_dbg(pdev, fmt, arg...) \
|
||||
dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg)
|
||||
|
||||
/*
|
||||
Set the number of I2C instance max
|
||||
Intel EG20T PCH : 1ch
|
||||
OKI SEMICONDUCTOR ML7213 IOH : 2ch
|
||||
*/
|
||||
#define PCH_I2C_MAX_DEV 2
|
||||
|
||||
/**
|
||||
* struct i2c_algo_pch_data - for I2C driver functionalities
|
||||
* @pch_adapter: stores the reference to i2c_adapter structure
|
||||
@ -156,12 +163,14 @@ struct i2c_algo_pch_data {
|
||||
* @pch_data: stores a list of i2c_algo_pch_data
|
||||
* @pch_i2c_suspended: specifies whether the system is suspended or not
|
||||
* perhaps with more lines and words.
|
||||
* @ch_num: specifies the number of i2c instance
|
||||
*
|
||||
* pch_data has as many elements as maximum I2C channels
|
||||
*/
|
||||
struct adapter_info {
|
||||
struct i2c_algo_pch_data pch_data;
|
||||
struct i2c_algo_pch_data pch_data[PCH_I2C_MAX_DEV];
|
||||
bool pch_i2c_suspended;
|
||||
int ch_num;
|
||||
};
|
||||
|
||||
|
||||
@ -170,8 +179,13 @@ static int pch_clk = 50000; /* specifies I2C clock speed in KHz */
|
||||
static wait_queue_head_t pch_event;
|
||||
static DEFINE_MUTEX(pch_mutex);
|
||||
|
||||
/* Definition for ML7213 by OKI SEMICONDUCTOR */
|
||||
#define PCI_VENDOR_ID_ROHM 0x10DB
|
||||
#define PCI_DEVICE_ID_ML7213_I2C 0x802D
|
||||
|
||||
static struct pci_device_id __devinitdata pch_pcidev_id[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_I2C)},
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, },
|
||||
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
|
||||
{0,}
|
||||
};
|
||||
|
||||
@ -212,8 +226,7 @@ static void pch_i2c_init(struct i2c_algo_pch_data *adap)
|
||||
/* Initialize I2C registers */
|
||||
iowrite32(0x21, p + PCH_I2CNF);
|
||||
|
||||
pch_setbit(adap->pch_base_address, PCH_I2CCTL,
|
||||
PCH_I2CCTL_I2CMEN);
|
||||
pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_I2CCTL_I2CMEN);
|
||||
|
||||
if (pch_i2c_speed != 400)
|
||||
pch_i2c_speed = 100;
|
||||
@ -255,7 +268,7 @@ static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
|
||||
* @timeout: waiting time counter (us).
|
||||
*/
|
||||
static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
|
||||
s32 timeout)
|
||||
s32 timeout)
|
||||
{
|
||||
void __iomem *p = adap->pch_base_address;
|
||||
|
||||
@ -475,8 +488,8 @@ static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap)
|
||||
* @last: specifies whether last message or not.
|
||||
* @first: specifies whether first message or not.
|
||||
*/
|
||||
s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
|
||||
u32 last, u32 first)
|
||||
static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
|
||||
u32 last, u32 first)
|
||||
{
|
||||
struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
|
||||
|
||||
@ -569,10 +582,10 @@ s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
|
||||
}
|
||||
|
||||
/**
|
||||
* pch_i2c_cb_ch0() - Interrupt handler Call back function
|
||||
* pch_i2c_cb() - Interrupt handler Call back function
|
||||
* @adap: Pointer to struct i2c_algo_pch_data.
|
||||
*/
|
||||
static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap)
|
||||
static void pch_i2c_cb(struct i2c_algo_pch_data *adap)
|
||||
{
|
||||
u32 sts;
|
||||
void __iomem *p = adap->pch_base_address;
|
||||
@ -600,24 +613,30 @@ static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap)
|
||||
*/
|
||||
static irqreturn_t pch_i2c_handler(int irq, void *pData)
|
||||
{
|
||||
s32 reg_val;
|
||||
u32 reg_val;
|
||||
int flag;
|
||||
int i;
|
||||
struct adapter_info *adap_info = pData;
|
||||
void __iomem *p;
|
||||
u32 mode;
|
||||
|
||||
struct i2c_algo_pch_data *adap_data = (struct i2c_algo_pch_data *)pData;
|
||||
void __iomem *p = adap_data->pch_base_address;
|
||||
u32 mode = ioread32(p + PCH_I2CMOD) & (BUFFER_MODE | EEPROM_SR_MODE);
|
||||
|
||||
if (mode != NORMAL_MODE) {
|
||||
pch_err(adap_data, "I2C mode is not supported\n");
|
||||
return IRQ_NONE;
|
||||
for (i = 0, flag = 0; i < adap_info->ch_num; i++) {
|
||||
p = adap_info->pch_data[i].pch_base_address;
|
||||
mode = ioread32(p + PCH_I2CMOD);
|
||||
mode &= BUFFER_MODE | EEPROM_SR_MODE;
|
||||
if (mode != NORMAL_MODE) {
|
||||
pch_err(adap_info->pch_data,
|
||||
"I2C-%d mode(%d) is not supported\n", mode, i);
|
||||
continue;
|
||||
}
|
||||
reg_val = ioread32(p + PCH_I2CSR);
|
||||
if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) {
|
||||
pch_i2c_cb(&adap_info->pch_data[i]);
|
||||
flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
reg_val = ioread32(p + PCH_I2CSR);
|
||||
if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT))
|
||||
pch_i2c_cb_ch0(adap_data);
|
||||
else
|
||||
return IRQ_NONE;
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return flag ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -627,7 +646,7 @@ static irqreturn_t pch_i2c_handler(int irq, void *pData)
|
||||
* @num: number of messages.
|
||||
*/
|
||||
static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg *msgs, s32 num)
|
||||
struct i2c_msg *msgs, s32 num)
|
||||
{
|
||||
struct i2c_msg *pmsg;
|
||||
u32 i = 0;
|
||||
@ -710,11 +729,13 @@ static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap)
|
||||
}
|
||||
|
||||
static int __devinit pch_i2c_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
void __iomem *base_addr;
|
||||
s32 ret;
|
||||
int ret;
|
||||
int i, j;
|
||||
struct adapter_info *adap_info;
|
||||
struct i2c_adapter *pch_adap;
|
||||
|
||||
pch_pci_dbg(pdev, "Entered.\n");
|
||||
|
||||
@ -744,44 +765,48 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev,
|
||||
goto err_pci_iomap;
|
||||
}
|
||||
|
||||
adap_info->pch_i2c_suspended = false;
|
||||
/* Set the number of I2C channel instance */
|
||||
adap_info->ch_num = id->driver_data;
|
||||
|
||||
adap_info->pch_data.p_adapter_info = adap_info;
|
||||
for (i = 0; i < adap_info->ch_num; i++) {
|
||||
pch_adap = &adap_info->pch_data[i].pch_adapter;
|
||||
adap_info->pch_i2c_suspended = false;
|
||||
|
||||
adap_info->pch_data.pch_adapter.owner = THIS_MODULE;
|
||||
adap_info->pch_data.pch_adapter.class = I2C_CLASS_HWMON;
|
||||
strcpy(adap_info->pch_data.pch_adapter.name, KBUILD_MODNAME);
|
||||
adap_info->pch_data.pch_adapter.algo = &pch_algorithm;
|
||||
adap_info->pch_data.pch_adapter.algo_data =
|
||||
&adap_info->pch_data;
|
||||
adap_info->pch_data[i].p_adapter_info = adap_info;
|
||||
|
||||
/* (i * 0x80) + base_addr; */
|
||||
adap_info->pch_data.pch_base_address = base_addr;
|
||||
pch_adap->owner = THIS_MODULE;
|
||||
pch_adap->class = I2C_CLASS_HWMON;
|
||||
strcpy(pch_adap->name, KBUILD_MODNAME);
|
||||
pch_adap->algo = &pch_algorithm;
|
||||
pch_adap->algo_data = &adap_info->pch_data[i];
|
||||
|
||||
adap_info->pch_data.pch_adapter.dev.parent = &pdev->dev;
|
||||
/* base_addr + offset; */
|
||||
adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i;
|
||||
|
||||
ret = i2c_add_adapter(&(adap_info->pch_data.pch_adapter));
|
||||
pch_adap->dev.parent = &pdev->dev;
|
||||
|
||||
if (ret) {
|
||||
pch_pci_err(pdev, "i2c_add_adapter FAILED\n");
|
||||
goto err_i2c_add_adapter;
|
||||
ret = i2c_add_adapter(pch_adap);
|
||||
if (ret) {
|
||||
pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i);
|
||||
goto err_i2c_add_adapter;
|
||||
}
|
||||
|
||||
pch_i2c_init(&adap_info->pch_data[i]);
|
||||
}
|
||||
|
||||
pch_i2c_init(&adap_info->pch_data);
|
||||
ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
|
||||
KBUILD_MODNAME, &adap_info->pch_data);
|
||||
KBUILD_MODNAME, adap_info);
|
||||
if (ret) {
|
||||
pch_pci_err(pdev, "request_irq FAILED\n");
|
||||
goto err_request_irq;
|
||||
goto err_i2c_add_adapter;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, adap_info);
|
||||
pch_pci_dbg(pdev, "returns %d.\n", ret);
|
||||
return 0;
|
||||
|
||||
err_request_irq:
|
||||
i2c_del_adapter(&(adap_info->pch_data.pch_adapter));
|
||||
err_i2c_add_adapter:
|
||||
for (j = 0; j < i; j++)
|
||||
i2c_del_adapter(&adap_info->pch_data[j].pch_adapter);
|
||||
pci_iounmap(pdev, base_addr);
|
||||
err_pci_iomap:
|
||||
pci_release_regions(pdev);
|
||||
@ -794,17 +819,22 @@ err_pci_enable:
|
||||
|
||||
static void __devexit pch_i2c_remove(struct pci_dev *pdev)
|
||||
{
|
||||
int i;
|
||||
struct adapter_info *adap_info = pci_get_drvdata(pdev);
|
||||
|
||||
pch_i2c_disbl_int(&adap_info->pch_data);
|
||||
free_irq(pdev->irq, &adap_info->pch_data);
|
||||
i2c_del_adapter(&(adap_info->pch_data.pch_adapter));
|
||||
free_irq(pdev->irq, adap_info);
|
||||
|
||||
if (adap_info->pch_data.pch_base_address) {
|
||||
pci_iounmap(pdev, adap_info->pch_data.pch_base_address);
|
||||
adap_info->pch_data.pch_base_address = 0;
|
||||
for (i = 0; i < adap_info->ch_num; i++) {
|
||||
pch_i2c_disbl_int(&adap_info->pch_data[i]);
|
||||
i2c_del_adapter(&adap_info->pch_data[i].pch_adapter);
|
||||
}
|
||||
|
||||
if (adap_info->pch_data[0].pch_base_address)
|
||||
pci_iounmap(pdev, adap_info->pch_data[0].pch_base_address);
|
||||
|
||||
for (i = 0; i < adap_info->ch_num; i++)
|
||||
adap_info->pch_data[i].pch_base_address = 0;
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
|
||||
pci_release_regions(pdev);
|
||||
@ -817,17 +847,22 @@ static void __devexit pch_i2c_remove(struct pci_dev *pdev)
|
||||
static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
struct adapter_info *adap_info = pci_get_drvdata(pdev);
|
||||
void __iomem *p = adap_info->pch_data.pch_base_address;
|
||||
void __iomem *p = adap_info->pch_data[0].pch_base_address;
|
||||
|
||||
adap_info->pch_i2c_suspended = true;
|
||||
|
||||
while ((adap_info->pch_data.pch_i2c_xfer_in_progress)) {
|
||||
/* Wait until all channel transfers are completed */
|
||||
msleep(20);
|
||||
for (i = 0; i < adap_info->ch_num; i++) {
|
||||
while ((adap_info->pch_data[i].pch_i2c_xfer_in_progress)) {
|
||||
/* Wait until all channel transfers are completed */
|
||||
msleep(20);
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable the i2c interrupts */
|
||||
pch_i2c_disbl_int(&adap_info->pch_data);
|
||||
for (i = 0; i < adap_info->ch_num; i++)
|
||||
pch_i2c_disbl_int(&adap_info->pch_data[i]);
|
||||
|
||||
pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x "
|
||||
"invoked function pch_i2c_disbl_int successfully\n",
|
||||
@ -850,6 +885,7 @@ static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
|
||||
static int pch_i2c_resume(struct pci_dev *pdev)
|
||||
{
|
||||
int i;
|
||||
struct adapter_info *adap_info = pci_get_drvdata(pdev);
|
||||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
@ -862,7 +898,8 @@ static int pch_i2c_resume(struct pci_dev *pdev)
|
||||
|
||||
pci_enable_wake(pdev, PCI_D3hot, 0);
|
||||
|
||||
pch_i2c_init(&adap_info->pch_data);
|
||||
for (i = 0; i < adap_info->ch_num; i++)
|
||||
pch_i2c_init(&adap_info->pch_data[i]);
|
||||
|
||||
adap_info->pch_i2c_suspended = false;
|
||||
|
||||
@ -894,7 +931,7 @@ static void __exit pch_pci_exit(void)
|
||||
}
|
||||
module_exit(pch_pci_exit);
|
||||
|
||||
MODULE_DESCRIPTION("PCH I2C PCI Driver");
|
||||
MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH I2C Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.okisemi.com>");
|
||||
module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR));
|
||||
|
@ -118,6 +118,8 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
|
||||
{
|
||||
mxs_reset_block(i2c->regs);
|
||||
writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
|
||||
writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
|
||||
i2c->regs + MXS_I2C_QUEUECTRL_SET);
|
||||
}
|
||||
|
||||
static void mxs_i2c_pioq_setup_read(struct mxs_i2c_dev *i2c, u8 addr, int len,
|
||||
@ -347,8 +349,6 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
/* Do reset to enforce correct startup after pinmuxing */
|
||||
mxs_i2c_reset(i2c);
|
||||
writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
|
||||
i2c->regs + MXS_I2C_QUEUECTRL_SET);
|
||||
|
||||
adap = &i2c->adapter;
|
||||
strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name));
|
||||
|
176
drivers/i2c/busses/i2c-pxa-pci.c
Normal file
176
drivers/i2c/busses/i2c-pxa-pci.c
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* The CE4100's I2C device is more or less the same one as found on PXA.
|
||||
* It does not support slave mode, the register slightly moved. This PCI
|
||||
* device provides three bars, every contains a single I2C controller.
|
||||
*/
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#define CE4100_PCI_I2C_DEVS 3
|
||||
|
||||
struct ce4100_devices {
|
||||
struct platform_device *pdev[CE4100_PCI_I2C_DEVS];
|
||||
};
|
||||
|
||||
static struct platform_device *add_i2c_device(struct pci_dev *dev, int bar)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct i2c_pxa_platform_data pdata;
|
||||
struct resource res[2];
|
||||
struct device_node *child;
|
||||
static int devnum;
|
||||
int ret;
|
||||
|
||||
memset(&pdata, 0, sizeof(struct i2c_pxa_platform_data));
|
||||
memset(&res, 0, sizeof(res));
|
||||
|
||||
res[0].flags = IORESOURCE_MEM;
|
||||
res[0].start = pci_resource_start(dev, bar);
|
||||
res[0].end = pci_resource_end(dev, bar);
|
||||
|
||||
res[1].flags = IORESOURCE_IRQ;
|
||||
res[1].start = dev->irq;
|
||||
res[1].end = dev->irq;
|
||||
|
||||
for_each_child_of_node(dev->dev.of_node, child) {
|
||||
const void *prop;
|
||||
struct resource r;
|
||||
int ret;
|
||||
|
||||
ret = of_address_to_resource(child, 0, &r);
|
||||
if (ret < 0)
|
||||
continue;
|
||||
if (r.start != res[0].start)
|
||||
continue;
|
||||
if (r.end != res[0].end)
|
||||
continue;
|
||||
if (r.flags != res[0].flags)
|
||||
continue;
|
||||
|
||||
prop = of_get_property(child, "fast-mode", NULL);
|
||||
if (prop)
|
||||
pdata.fast_mode = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!child) {
|
||||
dev_err(&dev->dev, "failed to match a DT node for bar %d.\n",
|
||||
bar);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pdev = platform_device_alloc("ce4100-i2c", devnum);
|
||||
if (!pdev) {
|
||||
of_node_put(child);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
pdev->dev.parent = &dev->dev;
|
||||
pdev->dev.of_node = child;
|
||||
|
||||
ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
if (ret)
|
||||
goto err;
|
||||
devnum++;
|
||||
return pdev;
|
||||
err:
|
||||
platform_device_put(pdev);
|
||||
out:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static int __devinit ce4100_i2c_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
struct ce4100_devices *sds;
|
||||
|
||||
ret = pci_enable_device_mem(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!dev->dev.of_node) {
|
||||
dev_err(&dev->dev, "Missing device tree node.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
sds = kzalloc(sizeof(*sds), GFP_KERNEL);
|
||||
if (!sds)
|
||||
goto err_mem;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) {
|
||||
sds->pdev[i] = add_i2c_device(dev, i);
|
||||
if (IS_ERR(sds->pdev[i])) {
|
||||
while (--i >= 0)
|
||||
platform_device_unregister(sds->pdev[i]);
|
||||
goto err_dev_add;
|
||||
}
|
||||
}
|
||||
pci_set_drvdata(dev, sds);
|
||||
return 0;
|
||||
|
||||
err_dev_add:
|
||||
pci_set_drvdata(dev, NULL);
|
||||
kfree(sds);
|
||||
err_mem:
|
||||
pci_disable_device(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit ce4100_i2c_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct ce4100_devices *sds;
|
||||
unsigned int i;
|
||||
|
||||
sds = pci_get_drvdata(dev);
|
||||
pci_set_drvdata(dev, NULL);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sds->pdev); i++)
|
||||
platform_device_unregister(sds->pdev[i]);
|
||||
|
||||
pci_disable_device(dev);
|
||||
kfree(sds);
|
||||
}
|
||||
|
||||
static struct pci_device_id ce4100_i2c_devices[] __devinitdata = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ce4100_i2c_devices);
|
||||
|
||||
static struct pci_driver ce4100_i2c_driver = {
|
||||
.name = "ce4100_i2c",
|
||||
.id_table = ce4100_i2c_devices,
|
||||
.probe = ce4100_i2c_probe,
|
||||
.remove = __devexit_p(ce4100_i2c_remove),
|
||||
};
|
||||
|
||||
static int __init ce4100_i2c_init(void)
|
||||
{
|
||||
return pci_register_driver(&ce4100_i2c_driver);
|
||||
}
|
||||
module_init(ce4100_i2c_init);
|
||||
|
||||
static void __exit ce4100_i2c_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&ce4100_i2c_driver);
|
||||
}
|
||||
module_exit(ce4100_i2c_exit);
|
||||
|
||||
MODULE_DESCRIPTION("CE4100 PCI-I2C glue code for PXA's driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
|
@ -29,38 +29,75 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c-pxa.h>
|
||||
#include <linux/of_i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <plat/i2c.h>
|
||||
|
||||
#ifndef CONFIG_HAVE_CLK
|
||||
#define clk_get(dev, id) NULL
|
||||
#define clk_put(clk) do { } while (0)
|
||||
#define clk_disable(clk) do { } while (0)
|
||||
#define clk_enable(clk) do { } while (0)
|
||||
#endif
|
||||
|
||||
struct pxa_reg_layout {
|
||||
u32 ibmr;
|
||||
u32 idbr;
|
||||
u32 icr;
|
||||
u32 isr;
|
||||
u32 isar;
|
||||
};
|
||||
|
||||
enum pxa_i2c_types {
|
||||
REGS_PXA2XX,
|
||||
REGS_PXA3XX,
|
||||
REGS_CE4100,
|
||||
};
|
||||
|
||||
/*
|
||||
* I2C register offsets will be shifted 0 or 1 bit left, depending on
|
||||
* different SoCs
|
||||
* I2C registers definitions
|
||||
*/
|
||||
#define REG_SHIFT_0 (0 << 0)
|
||||
#define REG_SHIFT_1 (1 << 0)
|
||||
#define REG_SHIFT(d) ((d) & 0x1)
|
||||
static struct pxa_reg_layout pxa_reg_layout[] = {
|
||||
[REGS_PXA2XX] = {
|
||||
.ibmr = 0x00,
|
||||
.idbr = 0x08,
|
||||
.icr = 0x10,
|
||||
.isr = 0x18,
|
||||
.isar = 0x20,
|
||||
},
|
||||
[REGS_PXA3XX] = {
|
||||
.ibmr = 0x00,
|
||||
.idbr = 0x04,
|
||||
.icr = 0x08,
|
||||
.isr = 0x0c,
|
||||
.isar = 0x10,
|
||||
},
|
||||
[REGS_CE4100] = {
|
||||
.ibmr = 0x14,
|
||||
.idbr = 0x0c,
|
||||
.icr = 0x00,
|
||||
.isr = 0x04,
|
||||
/* no isar register */
|
||||
},
|
||||
};
|
||||
|
||||
static const struct platform_device_id i2c_pxa_id_table[] = {
|
||||
{ "pxa2xx-i2c", REG_SHIFT_1 },
|
||||
{ "pxa3xx-pwri2c", REG_SHIFT_0 },
|
||||
{ "pxa2xx-i2c", REGS_PXA2XX },
|
||||
{ "pxa3xx-pwri2c", REGS_PXA3XX },
|
||||
{ "ce4100-i2c", REGS_CE4100 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
|
||||
|
||||
/*
|
||||
* I2C registers and bit definitions
|
||||
* I2C bit definitions
|
||||
*/
|
||||
#define IBMR (0x00)
|
||||
#define IDBR (0x08)
|
||||
#define ICR (0x10)
|
||||
#define ISR (0x18)
|
||||
#define ISAR (0x20)
|
||||
|
||||
#define ICR_START (1 << 0) /* start bit */
|
||||
#define ICR_STOP (1 << 1) /* stop bit */
|
||||
@ -111,7 +148,11 @@ struct pxa_i2c {
|
||||
u32 icrlog[32];
|
||||
|
||||
void __iomem *reg_base;
|
||||
unsigned int reg_shift;
|
||||
void __iomem *reg_ibmr;
|
||||
void __iomem *reg_idbr;
|
||||
void __iomem *reg_icr;
|
||||
void __iomem *reg_isr;
|
||||
void __iomem *reg_isar;
|
||||
|
||||
unsigned long iobase;
|
||||
unsigned long iosize;
|
||||
@ -121,11 +162,11 @@ struct pxa_i2c {
|
||||
unsigned int fast_mode :1;
|
||||
};
|
||||
|
||||
#define _IBMR(i2c) ((i2c)->reg_base + (0x0 << (i2c)->reg_shift))
|
||||
#define _IDBR(i2c) ((i2c)->reg_base + (0x4 << (i2c)->reg_shift))
|
||||
#define _ICR(i2c) ((i2c)->reg_base + (0x8 << (i2c)->reg_shift))
|
||||
#define _ISR(i2c) ((i2c)->reg_base + (0xc << (i2c)->reg_shift))
|
||||
#define _ISAR(i2c) ((i2c)->reg_base + (0x10 << (i2c)->reg_shift))
|
||||
#define _IBMR(i2c) ((i2c)->reg_ibmr)
|
||||
#define _IDBR(i2c) ((i2c)->reg_idbr)
|
||||
#define _ICR(i2c) ((i2c)->reg_icr)
|
||||
#define _ISR(i2c) ((i2c)->reg_isr)
|
||||
#define _ISAR(i2c) ((i2c)->reg_isar)
|
||||
|
||||
/*
|
||||
* I2C Slave mode address
|
||||
@ -418,7 +459,8 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c)
|
||||
writel(I2C_ISR_INIT, _ISR(i2c));
|
||||
writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c));
|
||||
|
||||
writel(i2c->slave_addr, _ISAR(i2c));
|
||||
if (i2c->reg_isar)
|
||||
writel(i2c->slave_addr, _ISAR(i2c));
|
||||
|
||||
/* set control register values */
|
||||
writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c));
|
||||
@ -729,8 +771,10 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
|
||||
*/
|
||||
ret = i2c->msg_idx;
|
||||
|
||||
if (timeout == 0)
|
||||
if (!timeout && i2c->msg_num) {
|
||||
i2c_pxa_scream_blue_murder(i2c, "timeout");
|
||||
ret = I2C_RETRY;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
@ -915,11 +959,16 @@ static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr)
|
||||
writel(icr, _ICR(i2c));
|
||||
}
|
||||
|
||||
#define VALID_INT_SOURCE (ISR_SSD | ISR_ALD | ISR_ITE | ISR_IRF | \
|
||||
ISR_SAD | ISR_BED)
|
||||
static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
|
||||
{
|
||||
struct pxa_i2c *i2c = dev_id;
|
||||
u32 isr = readl(_ISR(i2c));
|
||||
|
||||
if (!(isr & VALID_INT_SOURCE))
|
||||
return IRQ_NONE;
|
||||
|
||||
if (i2c_debug > 2 && 0) {
|
||||
dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n",
|
||||
__func__, isr, readl(_ICR(i2c)), readl(_IBMR(i2c)));
|
||||
@ -934,7 +983,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
|
||||
/*
|
||||
* Always clear all pending IRQs.
|
||||
*/
|
||||
writel(isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED), _ISR(i2c));
|
||||
writel(isr & VALID_INT_SOURCE, _ISR(i2c));
|
||||
|
||||
if (isr & ISR_SAD)
|
||||
i2c_pxa_slave_start(i2c, isr);
|
||||
@ -1001,6 +1050,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
|
||||
struct resource *res;
|
||||
struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
|
||||
const struct platform_device_id *id = platform_get_device_id(dev);
|
||||
enum pxa_i2c_types i2c_type = id->driver_data;
|
||||
int ret;
|
||||
int irq;
|
||||
|
||||
@ -1044,7 +1094,13 @@ static int i2c_pxa_probe(struct platform_device *dev)
|
||||
ret = -EIO;
|
||||
goto eremap;
|
||||
}
|
||||
i2c->reg_shift = REG_SHIFT(id->driver_data);
|
||||
|
||||
i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr;
|
||||
i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr;
|
||||
i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr;
|
||||
i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr;
|
||||
if (i2c_type != REGS_CE4100)
|
||||
i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
|
||||
|
||||
i2c->iobase = res->start;
|
||||
i2c->iosize = resource_size(res);
|
||||
@ -1072,7 +1128,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
|
||||
i2c->adap.algo = &i2c_pxa_pio_algorithm;
|
||||
} else {
|
||||
i2c->adap.algo = &i2c_pxa_algorithm;
|
||||
ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
|
||||
ret = request_irq(irq, i2c_pxa_handler, IRQF_SHARED,
|
||||
i2c->adap.name, i2c);
|
||||
if (ret)
|
||||
goto ereqirq;
|
||||
@ -1082,12 +1138,19 @@ static int i2c_pxa_probe(struct platform_device *dev)
|
||||
|
||||
i2c->adap.algo_data = i2c;
|
||||
i2c->adap.dev.parent = &dev->dev;
|
||||
#ifdef CONFIG_OF
|
||||
i2c->adap.dev.of_node = dev->dev.of_node;
|
||||
#endif
|
||||
|
||||
ret = i2c_add_numbered_adapter(&i2c->adap);
|
||||
if (i2c_type == REGS_CE4100)
|
||||
ret = i2c_add_adapter(&i2c->adap);
|
||||
else
|
||||
ret = i2c_add_numbered_adapter(&i2c->adap);
|
||||
if (ret < 0) {
|
||||
printk(KERN_INFO "I2C: Failed to add bus\n");
|
||||
goto eadapt;
|
||||
}
|
||||
of_i2c_register_devices(&i2c->adap);
|
||||
|
||||
platform_set_drvdata(dev, i2c);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user