diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt index afc04589eadf..27f2bc15298a 100644 --- a/Documentation/devicetree/bindings/eeprom/eeprom.txt +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt @@ -36,6 +36,8 @@ Optional properties: - read-only: this parameterless property disables writes to the eeprom + - size: total eeprom size in bytes + Example: eeprom@52 { diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt index bd6480b19535..e7106bfc1f13 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt @@ -7,7 +7,9 @@ Required Properties: - compatible : should be "aspeed,ast2400-i2c-bus" or "aspeed,ast2500-i2c-bus" - clocks : root clock of bus, should reference the APB - clock + clock in the second cell +- resets : phandle to reset controller with the reset number in + the second cell - interrupts : interrupt number - interrupt-parent : interrupt controller for bus, should reference a aspeed,ast2400-i2c-ic or aspeed,ast2500-i2c-ic @@ -40,7 +42,8 @@ i2c { #interrupt-cells = <1>; reg = <0x40 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <0>; interrupt-parent = <&i2c_ic>; diff --git a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt index 5b123e0e4cc2..64e6e656c345 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt @@ -6,6 +6,18 @@ davinci/keystone i2c interface contains. Required properties: - compatible: "ti,davinci-i2c" or "ti,keystone-i2c"; - reg : Offset and length of the register set for the device +- clocks: I2C functional clock phandle. + For 66AK2G this property should be set per binding, + Documentation/devicetree/bindings/clock/ti,sci-clk.txt + +SoC-specific Required Properties: + +The following are mandatory properties for Keystone 2 66AK2G SoCs only: + +- power-domains: Should contain a phandle to a PM domain provider node + and an args specifier containing the I2C device id + value. This property is as per the binding, + Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt Recommended properties : - interrupts : standard interrupt property. diff --git a/Documentation/devicetree/bindings/i2c/i2c-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-gpio.txt index 4f8ec947c6bd..38a05562d1d2 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-gpio.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-gpio.txt @@ -2,25 +2,39 @@ Device-Tree bindings for i2c gpio driver Required properties: - compatible = "i2c-gpio"; - - gpios: sda and scl gpio - + - sda-gpios: gpio used for the sda signal, this should be flagged as + active high using open drain with (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN) + from since the signal is by definition + open drain. + - scl-gpios: gpio used for the scl signal, this should be flagged as + active high using open drain with (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN) + from since the signal is by definition + open drain. Optional properties: - - i2c-gpio,sda-open-drain: sda as open drain - - i2c-gpio,scl-open-drain: scl as open drain - i2c-gpio,scl-output-only: scl as output only - i2c-gpio,delay-us: delay between GPIO operations (may depend on each platform) - i2c-gpio,timeout-ms: timeout to get data +Deprecated properties, do not use in new device tree sources: + - gpios: sda and scl gpio, alternative for {sda,scl}-gpios + - i2c-gpio,sda-open-drain: this means that something outside of our + control has put the GPIO line used for SDA into open drain mode, and + that something is not the GPIO chip. It is essentially an + inconsistency flag. + - i2c-gpio,scl-open-drain: this means that something outside of our + control has put the GPIO line used for SCL into open drain mode, and + that something is not the GPIO chip. It is essentially an + inconsistency flag. + Example nodes: +#include + i2c@0 { compatible = "i2c-gpio"; - gpios = <&pioA 23 0 /* sda */ - &pioA 24 0 /* scl */ - >; - i2c-gpio,sda-open-drain; - i2c-gpio,scl-open-drain; + sda-gpios = <&pioA 23 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + scl-gpios = <&pioA 24 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; i2c-gpio,delay-us = <2>; /* ~100 kHz */ #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux.txt b/Documentation/devicetree/bindings/i2c/i2c-mux.txt index 212e6779dc5c..b38f58a1c878 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mux.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mux.txt @@ -6,10 +6,10 @@ multiplexer/switch will have one child node for each child bus. Optional properties: - #address-cells = <1>; - This property is required is the i2c-mux child node does not exist. + This property is required if the i2c-mux child node does not exist. - #size-cells = <0>; - This property is required is the i2c-mux child node does not exist. + This property is required if the i2c-mux child node does not exist. - i2c-mux For i2c multiplexers/switches that have child nodes that are a mixture diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt index cad39aee9f73..a777477e4547 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt @@ -13,6 +13,7 @@ Required properties: "renesas,i2c-r8a7794" if the device is a part of a R8A7794 SoC. "renesas,i2c-r8a7795" if the device is a part of a R8A7795 SoC. "renesas,i2c-r8a7796" if the device is a part of a R8A7796 SoC. + "renesas,i2c-r8a77970" if the device is a part of a R8A77970 SoC. "renesas,rcar-gen1-i2c" for a generic R-Car Gen1 compatible device. "renesas,rcar-gen2-i2c" for a generic R-Car Gen2 or RZ/G1 compatible device. diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt index cee9d5055fa2..11263982470e 100644 --- a/Documentation/devicetree/bindings/i2c/i2c.txt +++ b/Documentation/devicetree/bindings/i2c/i2c.txt @@ -59,8 +59,8 @@ wants to support one of the below features, it should adapt the bindings below. interrupts used by the device. - interrupt-names - "irq" and "wakeup" names are recognized by I2C core, other names are - left to individual drivers. + "irq", "wakeup" and "smbus_alert" names are recognized by I2C core, + other names are left to individual drivers. - host-notify device uses SMBus host notify protocol instead of interrupt line. diff --git a/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.txt b/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.txt new file mode 100644 index 000000000000..4b2195571a49 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.txt @@ -0,0 +1,66 @@ +Binding for sbs-manager + +Required properties: +- compatible: ",", "sbs,sbs-charger" as fallback. The part + number compatible string might be used in order to take care of vendor + specific registers. +- reg: integer, i2c address of the device. Should be <0xa>. +Optional properties: +- gpio-controller: Marks the port as GPIO controller. + See "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt. +- #gpio-cells: Should be <2>. The first cell is the pin number, the second cell + is used to specify optional parameters: + See "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt. + +From OS view the device is basically an i2c-mux used to communicate with up to +four smart battery devices at address 0xb. The driver actually implements this +behaviour. So standard i2c-mux nodes can be used to register up to four slave +batteries. Channels will be numerated starting from 1 to 4. + +Example: + +batman@a { + compatible = "lltc,ltc1760", "sbs,sbs-manager"; + reg = <0x0a>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + battery@b { + compatible = "ti,bq2060", "sbs,sbs-battery"; + reg = <0x0b>; + sbs,battery-detect-gpios = <&batman 1 1>; + }; + }; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + battery@b { + compatible = "ti,bq2060", "sbs,sbs-battery"; + reg = <0x0b>; + sbs,battery-detect-gpios = <&batman 2 1>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + battery@b { + compatible = "ti,bq2060", "sbs,sbs-battery"; + reg = <0x0b>; + sbs,battery-detect-gpios = <&batman 3 1>; + }; + }; +}; diff --git a/MAINTAINERS b/MAINTAINERS index bb8eba5e9e4f..a76f02f64469 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2249,7 +2249,7 @@ F: include/linux/dmaengine.h F: include/linux/async_tx.h AT24 EEPROM DRIVER -M: Wolfram Sang +M: Bartosz Golaszewski L: linux-i2c@vger.kernel.org S: Maintained F: drivers/misc/eeprom/at24.c diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index f53c61813998..e70feec6fad5 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include @@ -320,42 +320,47 @@ void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr) /************************************************************************* * EP93xx i2c peripheral handling *************************************************************************/ -static struct i2c_gpio_platform_data ep93xx_i2c_data; + +/* All EP93xx devices use the same two GPIO pins for I2C bit-banging */ +static struct gpiod_lookup_table ep93xx_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + /* Use local offsets on gpiochip/port "G" */ + GPIO_LOOKUP_IDX("G", 1, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("G", 0, NULL, 1, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; static struct platform_device ep93xx_i2c_device = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &ep93xx_i2c_data, + .platform_data = NULL, }, }; /** * ep93xx_register_i2c - Register the i2c platform device. - * @data: platform specific i2c-gpio configuration (__initdata) * @devices: platform specific i2c bus device information (__initdata) * @num: the number of devices on the i2c bus */ -void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data, - struct i2c_board_info *devices, int num) +void __init ep93xx_register_i2c(struct i2c_board_info *devices, int num) { /* - * Set the EEPROM interface pin drive type control. - * Defines the driver type for the EECLK and EEDAT pins as either - * open drain, which will require an external pull-up, or a normal - * CMOS driver. + * FIXME: this just sets the two pins as non-opendrain, as no + * platforms tries to do that anyway. Flag the applicable lines + * as open drain in the GPIO_LOOKUP above and the driver or + * gpiolib will handle open drain/open drain emulation as need + * be. Right now i2c-gpio emulates open drain which is not + * optimal. */ - if (data->sda_is_open_drain && data->sda_pin != EP93XX_GPIO_LINE_EEDAT) - pr_warning("sda != EEDAT, open drain has no effect\n"); - if (data->scl_is_open_drain && data->scl_pin != EP93XX_GPIO_LINE_EECLK) - pr_warning("scl != EECLK, open drain has no effect\n"); - - __raw_writel((data->sda_is_open_drain << 1) | - (data->scl_is_open_drain << 0), + __raw_writel((0 << 1) | (0 << 0), EP93XX_GPIO_EEDRIVE); - ep93xx_i2c_data = *data; i2c_register_board_info(0, devices, num); + gpiod_add_lookup_table(&ep93xx_i2c_gpiod_table); platform_device_register(&ep93xx_i2c_device); } diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c index 7a7f280b07d7..8e89ec8b6f0f 100644 --- a/arch/arm/mach-ep93xx/edb93xx.c +++ b/arch/arm/mach-ep93xx/edb93xx.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -61,14 +60,6 @@ static struct ep93xx_eth_data __initdata edb93xx_eth_data = { /************************************************************************* * EDB93xx i2c peripheral handling *************************************************************************/ -static struct i2c_gpio_platform_data __initdata edb93xx_i2c_gpio_data = { - .sda_pin = EP93XX_GPIO_LINE_EEDAT, - .sda_is_open_drain = 0, - .scl_pin = EP93XX_GPIO_LINE_EECLK, - .scl_is_open_drain = 0, - .udelay = 0, /* default to 100 kHz */ - .timeout = 0, /* default to 100 ms */ -}; static struct i2c_board_info __initdata edb93xxa_i2c_board_info[] = { { @@ -86,13 +77,11 @@ static void __init edb93xx_register_i2c(void) { if (machine_is_edb9302a() || machine_is_edb9307a() || machine_is_edb9315a()) { - ep93xx_register_i2c(&edb93xx_i2c_gpio_data, - edb93xxa_i2c_board_info, + ep93xx_register_i2c(edb93xxa_i2c_board_info, ARRAY_SIZE(edb93xxa_i2c_board_info)); } else if (machine_is_edb9302() || machine_is_edb9307() || machine_is_edb9312() || machine_is_edb9315()) { - ep93xx_register_i2c(&edb93xx_i2c_gpio_data, - edb93xx_i2c_board_info, + ep93xx_register_i2c(edb93xx_i2c_board_info, ARRAY_SIZE(edb93xx_i2c_board_info)); } } diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h index 3bbe1591013e..6c41c794bed5 100644 --- a/arch/arm/mach-ep93xx/include/mach/platform.h +++ b/arch/arm/mach-ep93xx/include/mach/platform.h @@ -8,7 +8,6 @@ #include struct device; -struct i2c_gpio_platform_data; struct i2c_board_info; struct spi_board_info; struct platform_device; @@ -37,8 +36,7 @@ void ep93xx_register_flash(unsigned int width, resource_size_t start, resource_size_t size); void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr); -void ep93xx_register_i2c(struct i2c_gpio_platform_data *data, - struct i2c_board_info *devices, int num); +void ep93xx_register_i2c(struct i2c_board_info *devices, int num); void ep93xx_register_spi(struct ep93xx_spi_info *info, struct spi_board_info *devices, int num); void ep93xx_register_fb(struct ep93xxfb_mach_info *data); diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c index c7a40f245892..e61f3dee24c2 100644 --- a/arch/arm/mach-ep93xx/simone.c +++ b/arch/arm/mach-ep93xx/simone.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -129,15 +128,6 @@ static struct ep93xx_spi_info simone_spi_info __initdata = { .use_dma = 1, }; -static struct i2c_gpio_platform_data __initdata simone_i2c_gpio_data = { - .sda_pin = EP93XX_GPIO_LINE_EEDAT, - .sda_is_open_drain = 0, - .scl_pin = EP93XX_GPIO_LINE_EECLK, - .scl_is_open_drain = 0, - .udelay = 0, - .timeout = 0, -}; - static struct i2c_board_info __initdata simone_i2c_board_info[] = { { I2C_BOARD_INFO("ds1337", 0x68), @@ -161,7 +151,7 @@ static void __init simone_init_machine(void) ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_8M); ep93xx_register_eth(&simone_eth_data, 1); ep93xx_register_fb(&simone_fb_info); - ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info, + ep93xx_register_i2c(simone_i2c_board_info, ARRAY_SIZE(simone_i2c_board_info)); ep93xx_register_spi(&simone_spi_info, simone_spi_devices, ARRAY_SIZE(simone_spi_devices)); diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c index 8b29398f4dc7..45940c1d7787 100644 --- a/arch/arm/mach-ep93xx/snappercl15.c +++ b/arch/arm/mach-ep93xx/snappercl15.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -127,15 +126,6 @@ static struct ep93xx_eth_data __initdata snappercl15_eth_data = { .phy_id = 1, }; -static struct i2c_gpio_platform_data __initdata snappercl15_i2c_gpio_data = { - .sda_pin = EP93XX_GPIO_LINE_EEDAT, - .sda_is_open_drain = 0, - .scl_pin = EP93XX_GPIO_LINE_EECLK, - .scl_is_open_drain = 0, - .udelay = 0, - .timeout = 0, -}; - static struct i2c_board_info __initdata snappercl15_i2c_data[] = { { /* Audio codec */ @@ -161,7 +151,7 @@ static void __init snappercl15_init_machine(void) { ep93xx_init_devices(); ep93xx_register_eth(&snappercl15_eth_data, 1); - ep93xx_register_i2c(&snappercl15_i2c_gpio_data, snappercl15_i2c_data, + ep93xx_register_i2c(snappercl15_i2c_data, ARRAY_SIZE(snappercl15_i2c_data)); ep93xx_register_fb(&snappercl15_fb_info); snappercl15_register_audio(); diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c index 1daf9441058c..5a0b6187990a 100644 --- a/arch/arm/mach-ep93xx/vision_ep9307.c +++ b/arch/arm/mach-ep93xx/vision_ep9307.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -144,10 +143,6 @@ static struct pca953x_platform_data pca953x_77_gpio_data = { /************************************************************************* * I2C Bus *************************************************************************/ -static struct i2c_gpio_platform_data vision_i2c_gpio_data __initdata = { - .sda_pin = EP93XX_GPIO_LINE_EEDAT, - .scl_pin = EP93XX_GPIO_LINE_EECLK, -}; static struct i2c_board_info vision_i2c_info[] __initdata = { { @@ -289,7 +284,7 @@ static void __init vision_init_machine(void) vision_i2c_info[1].irq = gpio_to_irq(EP93XX_GPIO_LINE_F(7)); - ep93xx_register_i2c(&vision_i2c_gpio_data, vision_i2c_info, + ep93xx_register_i2c(vision_i2c_info, ARRAY_SIZE(vision_i2c_info)); ep93xx_register_spi(&vision_spi_master, vision_spi_board_info, ARRAY_SIZE(vision_spi_board_info)); diff --git a/arch/arm/mach-ixp4xx/avila-setup.c b/arch/arm/mach-ixp4xx/avila-setup.c index 186df64ceae7..77def6169f50 100644 --- a/arch/arm/mach-ixp4xx/avila-setup.c +++ b/arch/arm/mach-ixp4xx/avila-setup.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -50,16 +50,21 @@ static struct platform_device avila_flash = { .resource = &avila_flash_resource, }; -static struct i2c_gpio_platform_data avila_i2c_gpio_data = { - .sda_pin = AVILA_SDA_PIN, - .scl_pin = AVILA_SCL_PIN, +static struct gpiod_lookup_table avila_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", AVILA_SDA_PIN, + NULL, 0, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", AVILA_SCL_PIN, + NULL, 1, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, }; static struct platform_device avila_i2c_gpio = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &avila_i2c_gpio_data, + .platform_data = NULL, }, }; @@ -148,6 +153,8 @@ static void __init avila_init(void) avila_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + gpiod_add_lookup_table(&avila_i2c_gpiod_table); + platform_add_devices(avila_devices, ARRAY_SIZE(avila_devices)); avila_pata_resources[0].start = IXP4XX_EXP_BUS_BASE(1); diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c index 19839bba7f17..ac97a4599034 100644 --- a/arch/arm/mach-ixp4xx/dsmg600-setup.c +++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include @@ -69,16 +69,21 @@ static struct platform_device dsmg600_flash = { .resource = &dsmg600_flash_resource, }; -static struct i2c_gpio_platform_data dsmg600_i2c_gpio_data = { - .sda_pin = DSMG600_SDA_PIN, - .scl_pin = DSMG600_SCL_PIN, +static struct gpiod_lookup_table dsmg600_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", DSMG600_SDA_PIN, + NULL, 0, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", DSMG600_SCL_PIN, + NULL, 1, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, }; static struct platform_device dsmg600_i2c_gpio = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &dsmg600_i2c_gpio_data, + .platform_data = NULL, }, }; @@ -270,6 +275,7 @@ static void __init dsmg600_init(void) dsmg600_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + gpiod_add_lookup_table(&dsmg600_i2c_gpiod_table); i2c_register_board_info(0, dsmg600_i2c_board_info, ARRAY_SIZE(dsmg600_i2c_board_info)); diff --git a/arch/arm/mach-ixp4xx/fsg-setup.c b/arch/arm/mach-ixp4xx/fsg-setup.c index 6e32cbc4f590..033f79b35d51 100644 --- a/arch/arm/mach-ixp4xx/fsg-setup.c +++ b/arch/arm/mach-ixp4xx/fsg-setup.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -55,16 +55,21 @@ static struct platform_device fsg_flash = { .resource = &fsg_flash_resource, }; -static struct i2c_gpio_platform_data fsg_i2c_gpio_data = { - .sda_pin = FSG_SDA_PIN, - .scl_pin = FSG_SCL_PIN, +static struct gpiod_lookup_table fsg_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", FSG_SDA_PIN, + NULL, 0, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", FSG_SCL_PIN, + NULL, 1, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, }; static struct platform_device fsg_i2c_gpio = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &fsg_i2c_gpio_data, + .platform_data = NULL, }, }; @@ -197,6 +202,7 @@ static void __init fsg_init(void) /* Configure CS2 for operation, 8bit and writable */ *IXP4XX_EXP_CS2 = 0xbfff0002; + gpiod_add_lookup_table(&fsg_i2c_gpiod_table); i2c_register_board_info(0, fsg_i2c_board_info, ARRAY_SIZE(fsg_i2c_board_info)); diff --git a/arch/arm/mach-ixp4xx/goramo_mlr.c b/arch/arm/mach-ixp4xx/goramo_mlr.c index 145ec5c1b0eb..4d805080020e 100644 --- a/arch/arm/mach-ixp4xx/goramo_mlr.c +++ b/arch/arm/mach-ixp4xx/goramo_mlr.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -79,6 +78,12 @@ static u32 hw_bits = 0xFFFFFFFD; /* assume all hardware present */; static u8 control_value; +/* + * FIXME: this is reimplementing I2C bit-bangining. Move this + * over to using driver/i2c/busses/i2c-gpio.c like all other boards + * and register proper I2C device(s) on the bus for this. (See + * other IXP4xx boards for examples.) + */ static void set_scl(u8 value) { gpio_set_value(GPIO_SCL, !!value); @@ -217,20 +222,6 @@ static struct platform_device device_flash = { .resource = &flash_resource, }; - -/* I^2C interface */ -static struct i2c_gpio_platform_data i2c_data = { - .sda_pin = GPIO_SDA, - .scl_pin = GPIO_SCL, -}; - -static struct platform_device device_i2c = { - .name = "i2c-gpio", - .id = 0, - .dev = { .platform_data = &i2c_data }, -}; - - /* IXP425 2 UART ports */ static struct resource uart_resources[] = { { @@ -412,9 +403,6 @@ static void __init gmlr_init(void) if (hw_bits & CFG_HW_HAS_HSS1) device_tab[devices++] = &device_hss_tab[1]; /* max index 5 */ - if (hw_bits & CFG_HW_HAS_EEPROM) - device_tab[devices++] = &device_i2c; /* max index 6 */ - gpio_request(GPIO_SCL, "SCL/clock"); gpio_request(GPIO_SDA, "SDA/data"); gpio_request(GPIO_STR, "strobe"); diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index 8f5e01527b1b..b168e2fbdbeb 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -123,16 +123,21 @@ static struct platform_device ixdp425_flash_nand = { }; #endif /* CONFIG_MTD_NAND_PLATFORM */ -static struct i2c_gpio_platform_data ixdp425_i2c_gpio_data = { - .sda_pin = IXDP425_SDA_PIN, - .scl_pin = IXDP425_SCL_PIN, +static struct gpiod_lookup_table ixdp425_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", IXDP425_SDA_PIN, + NULL, 0, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", IXDP425_SCL_PIN, + NULL, 1, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, }; static struct platform_device ixdp425_i2c_gpio = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &ixdp425_i2c_gpio_data, + .platform_data = NULL, }, }; @@ -246,6 +251,7 @@ static void __init ixdp425_init(void) ixdp425_uart_data[1].flags = 0; } + gpiod_add_lookup_table(&ixdp425_i2c_gpiod_table); platform_add_devices(ixdp425_devices, ARRAY_SIZE(ixdp425_devices)); } diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c index b6d731241317..435602085408 100644 --- a/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -101,16 +101,21 @@ static struct platform_device nas100d_leds = { .dev.platform_data = &nas100d_led_data, }; -static struct i2c_gpio_platform_data nas100d_i2c_gpio_data = { - .sda_pin = NAS100D_SDA_PIN, - .scl_pin = NAS100D_SCL_PIN, +static struct gpiod_lookup_table nas100d_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", NAS100D_SDA_PIN, + NULL, 0, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", NAS100D_SCL_PIN, + NULL, 1, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, }; static struct platform_device nas100d_i2c_gpio = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &nas100d_i2c_gpio_data, + .platform_data = NULL, }, }; @@ -281,6 +286,7 @@ static void __init nas100d_init(void) nas100d_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + gpiod_add_lookup_table(&nas100d_i2c_gpiod_table); i2c_register_board_info(0, nas100d_i2c_board_info, ARRAY_SIZE(nas100d_i2c_board_info)); diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c index bd8dc65b4ffc..91da63a7d7b5 100644 --- a/arch/arm/mach-ixp4xx/nslu2-setup.c +++ b/arch/arm/mach-ixp4xx/nslu2-setup.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -69,9 +69,14 @@ static struct platform_device nslu2_flash = { .resource = &nslu2_flash_resource, }; -static struct i2c_gpio_platform_data nslu2_i2c_gpio_data = { - .sda_pin = NSLU2_SDA_PIN, - .scl_pin = NSLU2_SCL_PIN, +static struct gpiod_lookup_table nslu2_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", NSLU2_SDA_PIN, + NULL, 0, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", NSLU2_SCL_PIN, + NULL, 1, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, }; static struct i2c_board_info __initdata nslu2_i2c_board_info [] = { @@ -116,7 +121,7 @@ static struct platform_device nslu2_i2c_gpio = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &nslu2_i2c_gpio_data, + .platform_data = NULL, }, }; @@ -251,6 +256,7 @@ static void __init nslu2_init(void) nslu2_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + gpiod_add_lookup_table(&nslu2_i2c_gpiod_table); i2c_register_board_info(0, nslu2_i2c_board_info, ARRAY_SIZE(nslu2_i2c_board_info)); diff --git a/arch/arm/mach-ks8695/board-acs5k.c b/arch/arm/mach-ks8695/board-acs5k.c index e4d709c8ed32..937eb1d47e7b 100644 --- a/arch/arm/mach-ks8695/board-acs5k.c +++ b/arch/arm/mach-ks8695/board-acs5k.c @@ -16,7 +16,7 @@ #include #include #include - +#include #include #include #include @@ -38,9 +38,17 @@ #include "generic.h" +static struct gpiod_lookup_table acs5k_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("KS8695", 4, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("KS8695", 5, NULL, 1, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct i2c_gpio_platform_data acs5k_i2c_device_platdata = { - .sda_pin = 4, - .scl_pin = 5, .udelay = 10, }; @@ -95,6 +103,7 @@ static struct i2c_board_info acs5k_i2c_devs[] __initdata = { static void acs5k_i2c_init(void) { /* The gpio interface */ + gpiod_add_lookup_table(&acs5k_i2c_gpiod_table); platform_device_register(&acs5k_i2c_device); /* I2C devices */ i2c_register_board_info(0, acs5k_i2c_devs, diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c index 29630061e700..5877e547cecd 100644 --- a/arch/arm/mach-pxa/palmz72.c +++ b/arch/arm/mach-pxa/palmz72.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -320,9 +321,17 @@ static struct soc_camera_link palmz72_iclink = { .flags = SOCAM_DATAWIDTH_8, }; +static struct gpiod_lookup_table palmz72_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", 118, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("gpio-pxa", 117, NULL, 1, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct i2c_gpio_platform_data palmz72_i2c_bus_data = { - .sda_pin = 118, - .scl_pin = 117, .udelay = 10, .timeout = 100, }; @@ -369,6 +378,7 @@ static void __init palmz72_camera_init(void) { palmz72_cam_gpio_init(); pxa_set_camera_info(&palmz72_pxacamera_platform_data); + gpiod_add_lookup_table(&palmz72_i2c_gpiod_table); platform_device_register(&palmz72_i2c_bus_device); platform_device_register(&palmz72_camera); } diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c index 8e89d91b206b..4185e7ff073f 100644 --- a/arch/arm/mach-pxa/viper.c +++ b/arch/arm/mach-pxa/viper.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -458,9 +459,17 @@ static struct platform_device smc91x_device = { }; /* i2c */ +static struct gpiod_lookup_table viper_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", VIPER_RTC_I2C_SDA_GPIO, + NULL, 0, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("gpio-pxa", VIPER_RTC_I2C_SCL_GPIO, + NULL, 1, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct i2c_gpio_platform_data i2c_bus_data = { - .sda_pin = VIPER_RTC_I2C_SDA_GPIO, - .scl_pin = VIPER_RTC_I2C_SCL_GPIO, .udelay = 10, .timeout = HZ, }; @@ -779,12 +788,20 @@ static int __init viper_tpm_setup(char *str) __setup("tpm=", viper_tpm_setup); +struct gpiod_lookup_table viper_tpm_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("gpio-pxa", VIPER_TPM_I2C_SDA_GPIO, + NULL, 0, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("gpio-pxa", VIPER_TPM_I2C_SCL_GPIO, + NULL, 1, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static void __init viper_tpm_init(void) { struct platform_device *tpm_device; struct i2c_gpio_platform_data i2c_tpm_data = { - .sda_pin = VIPER_TPM_I2C_SDA_GPIO, - .scl_pin = VIPER_TPM_I2C_SCL_GPIO, .udelay = 10, .timeout = HZ, }; @@ -794,6 +811,7 @@ static void __init viper_tpm_init(void) if (!viper_tpm) return; + gpiod_add_lookup_table(&viper_tpm_i2c_gpiod_table); tpm_device = platform_device_alloc("i2c-gpio", 2); if (tpm_device) { if (!platform_device_add_data(tpm_device, @@ -943,6 +961,7 @@ static void __init viper_init(void) smc91x_device.num_resources--; pxa_set_i2c_info(NULL); + gpiod_add_lookup_table(&viper_i2c_gpiod_table); pwm_add_table(viper_pwm_lookup, ARRAY_SIZE(viper_pwm_lookup)); platform_add_devices(viper_devs, ARRAY_SIZE(viper_devs)); diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c index e8d25a7bbcb8..7d4feb8a49ac 100644 --- a/arch/arm/mach-sa1100/simpad.c +++ b/arch/arm/mach-sa1100/simpad.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -324,9 +325,17 @@ static struct platform_device simpad_gpio_leds = { /* * i2c */ +static struct gpiod_lookup_table simpad_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("gpio", 21, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("gpio", 25, NULL, 1, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct i2c_gpio_platform_data simpad_i2c_data = { - .sda_pin = GPIO_GPIO21, - .scl_pin = GPIO_GPIO25, .udelay = 10, .timeout = HZ, }; @@ -381,6 +390,7 @@ static int __init simpad_init(void) ARRAY_SIZE(simpad_flash_resources)); sa11x0_register_mcp(&simpad_mcp_data); + gpiod_add_lookup_table(&simpad_i2c_gpiod_table); ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if(ret) printk(KERN_WARNING "simpad: Unable to register mq200 framebuffer device"); diff --git a/arch/blackfin/mach-bf533/boards/blackstamp.c b/arch/blackfin/mach-bf533/boards/blackstamp.c index 0ccf0cf4daaf..fab69c736515 100644 --- a/arch/blackfin/mach-bf533/boards/blackstamp.c +++ b/arch/blackfin/mach-bf533/boards/blackstamp.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -362,11 +363,17 @@ static struct platform_device bfin_device_gpiokeys = { #if IS_ENABLED(CONFIG_I2C_GPIO) #include +static struct gpiod_lookup_table bfin_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF8, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF9, NULL, 1, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct i2c_gpio_platform_data i2c_gpio_data = { - .sda_pin = GPIO_PF8, - .scl_pin = GPIO_PF9, - .sda_is_open_drain = 0, - .scl_is_open_drain = 0, .udelay = 40, }; /* This hasn't actually been used these pins * are (currently) free pins on the expansion connector */ @@ -462,7 +469,9 @@ static int __init blackstamp_init(void) int ret; printk(KERN_INFO "%s(): registering device resources\n", __func__); - +#if IS_ENABLED(CONFIG_I2C_GPIO) + gpiod_add_lookup_table(&bfin_i2c_gpiod_table); +#endif i2c_register_board_info(0, bfin_i2c_board_info, ARRAY_SIZE(bfin_i2c_board_info)); diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c index 3625e9eaa8a8..d64d270e9e62 100644 --- a/arch/blackfin/mach-bf533/boards/ezkit.c +++ b/arch/blackfin/mach-bf533/boards/ezkit.c @@ -19,6 +19,7 @@ #endif #include #include +#include #include #include #include @@ -390,11 +391,17 @@ static struct platform_device bfin_device_gpiokeys = { #if IS_ENABLED(CONFIG_I2C_GPIO) #include +static struct gpiod_lookup_table bfin_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF1, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF0, NULL, 1, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct i2c_gpio_platform_data i2c_gpio_data = { - .sda_pin = GPIO_PF1, - .scl_pin = GPIO_PF0, - .sda_is_open_drain = 0, - .scl_is_open_drain = 0, .udelay = 40, }; @@ -516,6 +523,9 @@ static struct platform_device *ezkit_devices[] __initdata = { static int __init ezkit_init(void) { printk(KERN_INFO "%s(): registering device resources\n", __func__); +#if IS_ENABLED(CONFIG_I2C_GPIO) + gpiod_add_lookup_table(&bfin_i2c_gpiod_table); +#endif platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices)); spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); i2c_register_board_info(0, bfin_i2c_board_info, diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c index 23eada79439c..27cbf2fa2c62 100644 --- a/arch/blackfin/mach-bf533/boards/stamp.c +++ b/arch/blackfin/mach-bf533/boards/stamp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -512,11 +513,17 @@ static struct platform_device bfin_device_gpiokeys = { #if IS_ENABLED(CONFIG_I2C_GPIO) #include +static struct gpiod_lookup_table bfin_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF2, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF3, NULL, 1, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct i2c_gpio_platform_data i2c_gpio_data = { - .sda_pin = GPIO_PF2, - .scl_pin = GPIO_PF3, - .sda_is_open_drain = 0, - .scl_is_open_drain = 0, .udelay = 10, }; @@ -848,6 +855,9 @@ static int __init stamp_init(void) printk(KERN_INFO "%s(): registering device resources\n", __func__); +#if IS_ENABLED(CONFIG_I2C_GPIO) + gpiod_add_lookup_table(&bfin_i2c_gpiod_table); +#endif i2c_register_board_info(0, bfin_i2c_board_info, ARRAY_SIZE(bfin_i2c_board_info)); diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c index 57d1c43726d9..acc5363f60c6 100644 --- a/arch/blackfin/mach-bf561/boards/ezkit.c +++ b/arch/blackfin/mach-bf561/boards/ezkit.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -379,11 +380,17 @@ static struct platform_device bfin_device_gpiokeys = { #if IS_ENABLED(CONFIG_I2C_GPIO) #include +static struct gpiod_lookup_table bfin_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF1, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("BFIN-GPIO", GPIO_PF0, NULL, 1, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct i2c_gpio_platform_data i2c_gpio_data = { - .sda_pin = GPIO_PF1, - .scl_pin = GPIO_PF0, - .sda_is_open_drain = 0, - .scl_is_open_drain = 0, .udelay = 10, }; @@ -633,6 +640,9 @@ static int __init ezkit_init(void) printk(KERN_INFO "%s(): registering device resources\n", __func__); +#if IS_ENABLED(CONFIG_I2C_GPIO) + gpiod_add_lookup_table(&bfin_i2c_gpiod_table); +#endif ret = platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices)); if (ret < 0) return ret; diff --git a/arch/mips/alchemy/board-gpr.c b/arch/mips/alchemy/board-gpr.c index 6fb6b3faa158..328d697e72b4 100644 --- a/arch/mips/alchemy/board-gpr.c +++ b/arch/mips/alchemy/board-gpr.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -218,10 +219,27 @@ static struct platform_device gpr_led_devices = { /* * I2C */ +static struct gpiod_lookup_table gpr_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + /* + * This should be on "GPIO2" which has base at 200 so + * the global numbers 209 and 210 should correspond to + * local offsets 9 and 10. + */ + GPIO_LOOKUP_IDX("alchemy-gpio2", 9, NULL, 0, + GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("alchemy-gpio2", 10, NULL, 1, + GPIO_ACTIVE_HIGH), + }, +}; + static struct i2c_gpio_platform_data gpr_i2c_data = { - .sda_pin = 209, + /* + * The open drain mode is hardwired somewhere or an electrical + * property of the alchemy GPIO controller. + */ .sda_is_open_drain = 1, - .scl_pin = 210, .scl_is_open_drain = 1, .udelay = 2, /* ~100 kHz */ .timeout = HZ, @@ -295,6 +313,7 @@ arch_initcall(gpr_pci_init); static int __init gpr_dev_init(void) { + gpiod_add_lookup_table(&gpr_i2c_gpiod_table); i2c_register_board_info(0, gpr_i2c_info, ARRAY_SIZE(gpr_i2c_info)); return platform_add_devices(gpr_devices, ARRAY_SIZE(gpr_devices)); diff --git a/arch/mips/ath79/mach-pb44.c b/arch/mips/ath79/mach-pb44.c index be78298dffb4..6b2c6f3baefa 100644 --- a/arch/mips/ath79/mach-pb44.c +++ b/arch/mips/ath79/mach-pb44.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include "machtypes.h" @@ -33,16 +33,21 @@ #define PB44_KEYS_POLL_INTERVAL 20 /* msecs */ #define PB44_KEYS_DEBOUNCE_INTERVAL (3 * PB44_KEYS_POLL_INTERVAL) -static struct i2c_gpio_platform_data pb44_i2c_gpio_data = { - .sda_pin = PB44_GPIO_I2C_SDA, - .scl_pin = PB44_GPIO_I2C_SCL, +static struct gpiod_lookup_table pb44_i2c_gpiod_table = { + .dev_id = "i2c-gpio", + .table = { + GPIO_LOOKUP_IDX("ath79-gpio", PB44_GPIO_I2C_SDA, + NULL, 0, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP_IDX("ath79-gpio", PB44_GPIO_I2C_SCL, + NULL, 1, GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, }; static struct platform_device pb44_i2c_gpio_device = { .name = "i2c-gpio", .id = 0, .dev = { - .platform_data = &pb44_i2c_gpio_data, + .platform_data = NULL, } }; @@ -103,6 +108,7 @@ static struct ath79_spi_platform_data pb44_spi_data = { static void __init pb44_init(void) { + gpiod_add_lookup_table(&pb44_i2c_gpiod_table); i2c_register_board_info(0, pb44_i2c_board_info, ARRAY_SIZE(pb44_i2c_board_info)); platform_device_register(&pb44_i2c_gpio_device); diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index d5999eb41c00..d553b0087947 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -116,6 +116,10 @@ static const struct apd_device_desc hip08_i2c_desc = { .setup = acpi_apd_setup, .fixed_clk_rate = 250000000, }; +static const struct apd_device_desc thunderx2_i2c_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 125000000, +}; #endif #else @@ -180,6 +184,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = { { "APMC0D0F", APD_ADDR(xgene_i2c_desc) }, { "BRCM900D", APD_ADDR(vulcan_spi_desc) }, { "CAV900D", APD_ADDR(vulcan_spi_desc) }, + { "CAV9007", APD_ADDR(thunderx2_i2c_desc) }, { "HISI02A1", APD_ADDR(hip07_i2c_desc) }, { "HISI02A2", APD_ADDR(hip08_i2c_desc) }, #endif diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 86dcd02cf602..641a5eb552cb 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3528,8 +3528,21 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, if (lflags & GPIO_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); + if (lflags & GPIO_OPEN_DRAIN) set_bit(FLAG_OPEN_DRAIN, &desc->flags); + else if (dflags & GPIOD_FLAGS_BIT_OPEN_DRAIN) { + /* + * This enforces open drain mode from the consumer side. + * This is necessary for some busses like I2C, but the lookup + * should *REALLY* have specified them as open drain in the + * first place, so print a little warning here. + */ + set_bit(FLAG_OPEN_DRAIN, &desc->flags); + gpiod_warn(desc, + "enforced open drain please flag it properly in DT/ACPI DSDT/board file\n"); + } + if (lflags & GPIO_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); if (lflags & GPIO_SLEEP_MAY_LOSE_VALUE) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 45a3f3ca29b3..009345d8f49d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -198,6 +198,11 @@ config I2C_CHT_WC SMBus controller found in the Intel Cherry Trail Whiskey Cove PMIC found on some Intel Cherry Trail systems. + Note this controller is hooked up to a TI bq24292i charger-IC, + combined with a FUSB302 Type-C port-controller as such it is advised + to also select CONFIG_CHARGER_BQ24190=m and CONFIG_TYPEC_FUSB302=m + (the fusb302 driver currently is in drivers/staging). + config I2C_NFORCE2 tristate "Nvidia nForce2, nForce3 and nForce4" depends on PCI diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 284f8670dbeb..7d4aeb4465b3 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -27,6 +27,7 @@ #include #include #include +#include #include /* I2C Register */ @@ -132,6 +133,7 @@ struct aspeed_i2c_bus { struct i2c_adapter adap; struct device *dev; void __iomem *base; + struct reset_control *rst; /* Synchronizes I/O mem access to base. */ spinlock_t lock; struct completion cmd_complete; @@ -847,6 +849,14 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) /* We just need the clock rate, we don't actually use the clk object. */ devm_clk_put(&pdev->dev, parent_clk); + bus->rst = devm_reset_control_get_shared(&pdev->dev, NULL); + if (IS_ERR(bus->rst)) { + dev_err(&pdev->dev, + "missing or invalid reset controller device tree entry"); + return PTR_ERR(bus->rst); + } + reset_control_deassert(bus->rst); + ret = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &bus->bus_frequency); if (ret < 0) { @@ -917,6 +927,8 @@ static int aspeed_i2c_remove_bus(struct platform_device *pdev) spin_unlock_irqrestore(&bus->lock, flags); + reset_control_assert(bus->rst); + i2c_del_adapter(&bus->adap); return 0; diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c index 190bbbc7bfee..0d05dadb2dc5 100644 --- a/drivers/i2c/busses/i2c-cht-wc.c +++ b/drivers/i2c/busses/i2c-cht-wc.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #define CHT_WC_I2C_CTRL 0x5e24 @@ -232,13 +234,35 @@ static const struct irq_chip cht_wc_i2c_irq_chip = { .name = "cht_wc_ext_chrg_irq_chip", }; +static const char * const bq24190_suppliers[] = { "fusb302-typec-source" }; + static const struct property_entry bq24190_props[] = { - PROPERTY_ENTRY_STRING("extcon-name", "cht_wcove_pwrsrc"), + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_suppliers), PROPERTY_ENTRY_BOOL("omit-battery-class"), PROPERTY_ENTRY_BOOL("disable-reset"), { } }; +static struct regulator_consumer_supply fusb302_consumer = { + .supply = "vbus", + /* Must match fusb302 dev_name in intel_cht_int33fe.c */ + .dev_name = "i2c-fusb302", +}; + +static const struct regulator_init_data bq24190_vbus_init_data = { + .constraints = { + /* The name is used in intel_cht_int33fe.c do not change. */ + .name = "cht_wc_usb_typec_vbus", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = &fusb302_consumer, + .num_consumer_supplies = 1, +}; + +static struct bq24190_platform_data bq24190_pdata = { + .regulator_init_data = &bq24190_vbus_init_data, +}; + static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) { struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); @@ -246,7 +270,9 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) struct i2c_board_info board_info = { .type = "bq24190", .addr = 0x6b, + .dev_name = "bq24190", .properties = bq24190_props, + .platform_data = &bq24190_pdata, }; int ret, reg, irq; @@ -314,11 +340,21 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) if (ret) goto remove_irq_domain; - board_info.irq = adap->client_irq; - adap->client = i2c_new_device(&adap->adapter, &board_info); - if (!adap->client) { - ret = -ENOMEM; - goto del_adapter; + /* + * Normally the Whiskey Cove PMIC is paired with a TI bq24292i charger, + * connected to this i2c bus, and a max17047 fuel-gauge and a fusb302 + * USB Type-C controller connected to another i2c bus. In this setup + * the max17047 and fusb302 devices are enumerated through an INT33FE + * ACPI device. If this device is present register an i2c-client for + * the TI bq24292i charger. + */ + if (acpi_dev_present("INT33FE", NULL, -1)) { + board_info.irq = adap->client_irq; + adap->client = i2c_new_device(&adap->adapter, &board_info); + if (!adap->client) { + ret = -ENOMEM; + goto del_adapter; + } } platform_set_drvdata(pdev, adap); @@ -335,7 +371,8 @@ static int cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev) { struct cht_wc_i2c_adap *adap = platform_get_drvdata(pdev); - i2c_unregister_device(adap->client); + if (adap->client) + i2c_unregister_device(adap->client); i2c_del_adapter(&adap->adapter); irq_domain_remove(adap->irq_domain); diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index b8c43535f16c..2ead9b9eebb7 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -36,6 +36,7 @@ #include #include #include +#include /* ----- global defines ----------------------------------------------- */ @@ -122,6 +123,9 @@ /* set the SDA GPIO low */ #define DAVINCI_I2C_DCLR_PDCLR1 BIT(1) +/* timeout for pm runtime autosuspend */ +#define DAVINCI_I2C_PM_TIMEOUT 1000 /* ms */ + struct davinci_i2c_dev { struct device *dev; void __iomem *base; @@ -500,7 +504,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) /* This should be 0 if all bytes were transferred * or dev->cmd_err denotes an error. */ - dev_err(dev->dev, "abnormal termination buf_len=%i\n", + dev_err(dev->dev, "abnormal termination buf_len=%zu\n", dev->buf_len); dev->terminate = 1; wmb(); @@ -541,10 +545,17 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); + ret = pm_runtime_get_sync(dev->dev); + if (ret < 0) { + dev_err(dev->dev, "Failed to runtime_get device: %d\n", ret); + pm_runtime_put_noidle(dev->dev); + return ret; + } + ret = i2c_davinci_wait_bus_not_busy(dev); if (ret < 0) { dev_warn(dev->dev, "timeout waiting for bus ready\n"); - return ret; + goto out; } for (i = 0; i < num; i++) { @@ -552,14 +563,19 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev_dbg(dev->dev, "%s [%d/%d] ret: %d\n", __func__, i + 1, num, ret); if (ret < 0) - return ret; + goto out; } + ret = num; #ifdef CONFIG_CPU_FREQ complete(&dev->xfr_complete); #endif - return num; +out: + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); + + return ret; } static u32 i2c_davinci_func(struct i2c_adapter *adap) @@ -599,6 +615,9 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) int count = 0; u16 w; + if (pm_runtime_suspended(dev->dev)) + return IRQ_NONE; + while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) { dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat); if (count++ == 100) { @@ -802,13 +821,24 @@ static int davinci_i2c_probe(struct platform_device *pdev) dev->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) return PTR_ERR(dev->clk); - clk_prepare_enable(dev->clk); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(dev->base)) { - r = PTR_ERR(dev->base); - goto err_unuse_clocks; + return PTR_ERR(dev->base); + } + + pm_runtime_set_autosuspend_delay(dev->dev, + DAVINCI_I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(dev->dev); + + pm_runtime_enable(dev->dev); + + r = pm_runtime_get_sync(dev->dev); + if (r < 0) { + dev_err(dev->dev, "failed to runtime_get device: %d\n", r); + pm_runtime_put_noidle(dev->dev); + return r; } i2c_davinci_init(dev); @@ -849,27 +879,40 @@ static int davinci_i2c_probe(struct platform_device *pdev) if (r) goto err_unuse_clocks; + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); + return 0; err_unuse_clocks: - clk_disable_unprepare(dev->clk); - dev->clk = NULL; + pm_runtime_dont_use_autosuspend(dev->dev); + pm_runtime_put_sync(dev->dev); + pm_runtime_disable(dev->dev); + return r; } static int davinci_i2c_remove(struct platform_device *pdev) { struct davinci_i2c_dev *dev = platform_get_drvdata(pdev); + int ret; i2c_davinci_cpufreq_deregister(dev); i2c_del_adapter(&dev->adapter); - clk_disable_unprepare(dev->clk); - dev->clk = NULL; + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&pdev->dev); + return ret; + } davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0); + pm_runtime_dont_use_autosuspend(dev->dev); + pm_runtime_put_sync(dev->dev); + pm_runtime_disable(dev->dev); + return 0; } @@ -880,7 +923,6 @@ static int davinci_i2c_suspend(struct device *dev) /* put I2C into reset */ davinci_i2c_reset_ctrl(i2c_dev, 0); - clk_disable_unprepare(i2c_dev->clk); return 0; } @@ -889,7 +931,6 @@ static int davinci_i2c_resume(struct device *dev) { struct davinci_i2c_dev *i2c_dev = dev_get_drvdata(dev); - clk_prepare_enable(i2c_dev->clk); /* take I2C out of reset */ davinci_i2c_reset_ctrl(i2c_dev, 1); @@ -899,6 +940,8 @@ static int davinci_i2c_resume(struct device *dev) static const struct dev_pm_ops davinci_i2c_pm = { .suspend = davinci_i2c_suspend, .resume = davinci_i2c_resume, + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; #define davinci_i2c_pm_ops (&davinci_i2c_pm) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 9fee4c054d3d..21bf619a86c5 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -280,6 +280,8 @@ struct dw_i2c_dev { int (*acquire_lock)(struct dw_i2c_dev *dev); void (*release_lock)(struct dw_i2c_dev *dev); bool pm_disabled; + bool suspended; + bool skip_resume; void (*disable)(struct dw_i2c_dev *dev); void (*disable_int)(struct dw_i2c_dev *dev); int (*init)(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 0e65b97842b4..58add69a441c 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -249,6 +249,14 @@ static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id) } } +static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev) +{ + pm_runtime_disable(dev->dev); + + if (dev->pm_disabled) + pm_runtime_put_noidle(dev->dev); +} + static int dw_i2c_plat_probe(struct platform_device *pdev) { struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -257,7 +265,9 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) u32 acpi_speed, ht = 0; struct resource *mem; int i, irq, ret; - const int supported_speeds[] = { 0, 100000, 400000, 1000000, 3400000 }; + static const int supported_speeds[] = { + 0, 100000, 400000, 1000000, 3400000 + }; irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -362,14 +372,17 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); adap->dev.of_node = pdev->dev.of_node; - if (dev->pm_disabled) { - pm_runtime_forbid(&pdev->dev); - } else { - pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - } + /* The code below assumes runtime PM to be disabled. */ + WARN_ON(pm_runtime_enabled(&pdev->dev)); + + pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + + if (dev->pm_disabled) + pm_runtime_get_noresume(&pdev->dev); + + pm_runtime_enable(&pdev->dev); if (dev->mode == DW_IC_SLAVE) ret = i2c_dw_probe_slave(dev); @@ -382,8 +395,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) return ret; exit_probe: - if (!dev->pm_disabled) - pm_runtime_disable(&pdev->dev); + dw_i2c_plat_pm_cleanup(dev); exit_reset: if (!IS_ERR_OR_NULL(dev->rst)) reset_control_assert(dev->rst); @@ -402,8 +414,8 @@ static int dw_i2c_plat_remove(struct platform_device *pdev) pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); - if (!dev->pm_disabled) - pm_runtime_disable(&pdev->dev); + dw_i2c_plat_pm_cleanup(dev); + if (!IS_ERR_OR_NULL(dev->rst)) reset_control_assert(dev->rst); @@ -437,13 +449,20 @@ static void dw_i2c_plat_complete(struct device *dev) #endif #ifdef CONFIG_PM -static int dw_i2c_plat_runtime_suspend(struct device *dev) +static int dw_i2c_plat_suspend(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); + if (i_dev->suspended) { + i_dev->skip_resume = true; + return 0; + } + i_dev->disable(i_dev); i2c_dw_plat_prepare_clk(i_dev, false); + i_dev->suspended = true; + return 0; } @@ -451,27 +470,27 @@ static int dw_i2c_plat_resume(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); + if (!i_dev->suspended) + return 0; + + if (i_dev->skip_resume) { + i_dev->skip_resume = false; + return 0; + } + i2c_dw_plat_prepare_clk(i_dev, true); i_dev->init(i_dev); + i_dev->suspended = false; + return 0; } -#ifdef CONFIG_PM_SLEEP -static int dw_i2c_plat_suspend(struct device *dev) -{ - pm_runtime_resume(dev); - return dw_i2c_plat_runtime_suspend(dev); -} -#endif - static const struct dev_pm_ops dw_i2c_dev_pm_ops = { .prepare = dw_i2c_plat_prepare, .complete = dw_i2c_plat_complete, - SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) - SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, - dw_i2c_plat_resume, - NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) + SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL) }; #define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops) diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 0ef8fcc6ac3a..d80ea6ce91bb 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -14,27 +14,17 @@ #include #include #include -#include +#include #include -#include struct i2c_gpio_private_data { + struct gpio_desc *sda; + struct gpio_desc *scl; struct i2c_adapter adap; struct i2c_algo_bit_data bit_data; struct i2c_gpio_platform_data pdata; }; -/* Toggle SDA by changing the direction of the pin */ -static void i2c_gpio_setsda_dir(void *data, int state) -{ - struct i2c_gpio_platform_data *pdata = data; - - if (state) - gpio_direction_input(pdata->sda_pin); - else - gpio_direction_output(pdata->sda_pin, 0); -} - /* * Toggle SDA by changing the output value of the pin. This is only * valid for pins configured as open drain (i.e. setting the value @@ -42,20 +32,9 @@ static void i2c_gpio_setsda_dir(void *data, int state) */ static void i2c_gpio_setsda_val(void *data, int state) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; - gpio_set_value(pdata->sda_pin, state); -} - -/* Toggle SCL by changing the direction of the pin. */ -static void i2c_gpio_setscl_dir(void *data, int state) -{ - struct i2c_gpio_platform_data *pdata = data; - - if (state) - gpio_direction_input(pdata->scl_pin); - else - gpio_direction_output(pdata->scl_pin, 0); + gpiod_set_value(priv->sda, state); } /* @@ -66,44 +45,23 @@ static void i2c_gpio_setscl_dir(void *data, int state) */ static void i2c_gpio_setscl_val(void *data, int state) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; - gpio_set_value(pdata->scl_pin, state); + gpiod_set_value(priv->scl, state); } static int i2c_gpio_getsda(void *data) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; - return gpio_get_value(pdata->sda_pin); + return gpiod_get_value(priv->sda); } static int i2c_gpio_getscl(void *data) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; - return gpio_get_value(pdata->scl_pin); -} - -static int of_i2c_gpio_get_pins(struct device_node *np, - unsigned int *sda_pin, unsigned int *scl_pin) -{ - if (of_gpio_count(np) < 2) - return -ENODEV; - - *sda_pin = of_get_gpio(np, 0); - *scl_pin = of_get_gpio(np, 1); - - if (*sda_pin == -EPROBE_DEFER || *scl_pin == -EPROBE_DEFER) - return -EPROBE_DEFER; - - if (!gpio_is_valid(*sda_pin) || !gpio_is_valid(*scl_pin)) { - pr_err("%pOF: invalid GPIO pins, sda=%d/scl=%d\n", - np, *sda_pin, *scl_pin); - return -ENODEV; - } - - return 0; + return gpiod_get_value(priv->scl); } static void of_i2c_gpio_get_props(struct device_node *np, @@ -124,72 +82,105 @@ static void of_i2c_gpio_get_props(struct device_node *np, of_property_read_bool(np, "i2c-gpio,scl-output-only"); } +static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, + const char *con_id, + unsigned int index, + enum gpiod_flags gflags) +{ + struct gpio_desc *retdesc; + int ret; + + retdesc = devm_gpiod_get(dev, con_id, gflags); + if (!IS_ERR(retdesc)) { + dev_dbg(dev, "got GPIO from name %s\n", con_id); + return retdesc; + } + + retdesc = devm_gpiod_get_index(dev, NULL, index, gflags); + if (!IS_ERR(retdesc)) { + dev_dbg(dev, "got GPIO from index %u\n", index); + return retdesc; + } + + ret = PTR_ERR(retdesc); + + /* FIXME: hack in the old code, is this really necessary? */ + if (ret == -EINVAL) + retdesc = ERR_PTR(-EPROBE_DEFER); + + /* This happens if the GPIO driver is not yet probed, let's defer */ + if (ret == -ENOENT) + retdesc = ERR_PTR(-EPROBE_DEFER); + + if (ret != -EPROBE_DEFER) + dev_err(dev, "error trying to get descriptor: %d\n", ret); + + return retdesc; +} + static int i2c_gpio_probe(struct platform_device *pdev) { struct i2c_gpio_private_data *priv; struct i2c_gpio_platform_data *pdata; struct i2c_algo_bit_data *bit_data; struct i2c_adapter *adap; - unsigned int sda_pin, scl_pin; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + enum gpiod_flags gflags; int ret; - /* First get the GPIO pins; if it fails, we'll defer the probe. */ - if (pdev->dev.of_node) { - ret = of_i2c_gpio_get_pins(pdev->dev.of_node, - &sda_pin, &scl_pin); - if (ret) - return ret; - } else { - if (!dev_get_platdata(&pdev->dev)) - return -ENXIO; - pdata = dev_get_platdata(&pdev->dev); - sda_pin = pdata->sda_pin; - scl_pin = pdata->scl_pin; - } - - ret = devm_gpio_request(&pdev->dev, sda_pin, "sda"); - if (ret) { - if (ret == -EINVAL) - ret = -EPROBE_DEFER; /* Try again later */ - return ret; - } - ret = devm_gpio_request(&pdev->dev, scl_pin, "scl"); - if (ret) { - if (ret == -EINVAL) - ret = -EPROBE_DEFER; /* Try again later */ - return ret; - } - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + adap = &priv->adap; bit_data = &priv->bit_data; pdata = &priv->pdata; - if (pdev->dev.of_node) { - pdata->sda_pin = sda_pin; - pdata->scl_pin = scl_pin; - of_i2c_gpio_get_props(pdev->dev.of_node, pdata); + if (np) { + of_i2c_gpio_get_props(np, pdata); } else { - memcpy(pdata, dev_get_platdata(&pdev->dev), sizeof(*pdata)); + /* + * If all platform data settings are zero it is OK + * to not provide any platform data from the board. + */ + if (dev_get_platdata(dev)) + memcpy(pdata, dev_get_platdata(dev), sizeof(*pdata)); } - if (pdata->sda_is_open_drain) { - gpio_direction_output(pdata->sda_pin, 1); - bit_data->setsda = i2c_gpio_setsda_val; - } else { - gpio_direction_input(pdata->sda_pin); - bit_data->setsda = i2c_gpio_setsda_dir; - } + /* + * First get the GPIO pins; if it fails, we'll defer the probe. + * If the SDA line is marked from platform data or device tree as + * "open drain" it means something outside of our control is making + * this line being handled as open drain, and we should just handle + * it as any other output. Else we enforce open drain as this is + * required for an I2C bus. + */ + if (pdata->sda_is_open_drain) + gflags = GPIOD_OUT_HIGH; + else + gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; + priv->sda = i2c_gpio_get_desc(dev, "sda", 0, gflags); + if (IS_ERR(priv->sda)) + return PTR_ERR(priv->sda); - if (pdata->scl_is_open_drain || pdata->scl_is_output_only) { - gpio_direction_output(pdata->scl_pin, 1); - bit_data->setscl = i2c_gpio_setscl_val; - } else { - gpio_direction_input(pdata->scl_pin); - bit_data->setscl = i2c_gpio_setscl_dir; - } + /* + * If the SCL line is marked from platform data or device tree as + * "open drain" it means something outside of our control is making + * this line being handled as open drain, and we should just handle + * it as any other output. Else we enforce open drain as this is + * required for an I2C bus. + */ + if (pdata->scl_is_open_drain) + gflags = GPIOD_OUT_LOW; + else + gflags = GPIOD_OUT_LOW_OPEN_DRAIN; + priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags); + if (IS_ERR(priv->scl)) + return PTR_ERR(priv->scl); + + bit_data->setsda = i2c_gpio_setsda_val; + bit_data->setscl = i2c_gpio_setscl_val; if (!pdata->scl_is_output_only) bit_data->getscl = i2c_gpio_getscl; @@ -207,18 +198,18 @@ static int i2c_gpio_probe(struct platform_device *pdev) else bit_data->timeout = HZ / 10; /* 100 ms */ - bit_data->data = pdata; + bit_data->data = priv; adap->owner = THIS_MODULE; - if (pdev->dev.of_node) - strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); + if (np) + strlcpy(adap->name, dev_name(dev), sizeof(adap->name)); else snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); adap->algo_data = bit_data; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - adap->dev.parent = &pdev->dev; - adap->dev.of_node = pdev->dev.of_node; + adap->dev.parent = dev; + adap->dev.of_node = np; adap->nr = pdev->id; ret = i2c_bit_add_numbered_bus(adap); @@ -227,8 +218,13 @@ static int i2c_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); - dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n", - pdata->sda_pin, pdata->scl_pin, + /* + * FIXME: using global GPIO numbers is not helpful. If/when we + * get accessors to get the actual name of the GPIO line, + * from the descriptor, then provide that instead. + */ + dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n", + desc_to_gpio(priv->sda), desc_to_gpio(priv->scl), pdata->scl_is_output_only ? ", no clock stretching" : ""); diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index eb1d91b986fd..f038858b6c54 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -82,6 +82,7 @@ #include #include #include +#include #include #include @@ -280,6 +281,8 @@ #define ISR_COMPLETE(err) (ISR_COMPLETE_M | (ISR_STATUS_M & (err))) #define ISR_FATAL(err) (ISR_COMPLETE(err) | ISR_FATAL_M) +#define IMG_I2C_PM_TIMEOUT 1000 /* ms */ + enum img_i2c_mode { MODE_INACTIVE, MODE_RAW, @@ -408,6 +411,9 @@ struct img_i2c { unsigned int raw_timeout; }; +static int img_i2c_runtime_suspend(struct device *dev); +static int img_i2c_runtime_resume(struct device *dev); + static void img_i2c_writel(struct img_i2c *i2c, u32 offset, u32 value) { writel(value, i2c->base + offset); @@ -826,9 +832,9 @@ next_atomic_cmd: * Timer function to check if something has gone wrong in automatic mode (so we * don't have to handle so many interrupts just to catch an exception). */ -static void img_i2c_check_timer(unsigned long arg) +static void img_i2c_check_timer(struct timer_list *t) { - struct img_i2c *i2c = (struct img_i2c *)arg; + struct img_i2c *i2c = from_timer(i2c, t, check_timer); unsigned long flags; unsigned int line_status; @@ -1054,8 +1060,8 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, atomic = true; } - ret = clk_prepare_enable(i2c->scb_clk); - if (ret) + ret = pm_runtime_get_sync(adap->dev.parent); + if (ret < 0) return ret; for (i = 0; i < num; i++) { @@ -1131,7 +1137,8 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, break; } - clk_disable_unprepare(i2c->scb_clk); + pm_runtime_mark_last_busy(adap->dev.parent); + pm_runtime_put_autosuspend(adap->dev.parent); return i2c->msg_status ? i2c->msg_status : num; } @@ -1149,12 +1156,13 @@ static const struct i2c_algorithm img_i2c_algo = { static int img_i2c_init(struct img_i2c *i2c) { unsigned int clk_khz, bitrate_khz, clk_period, tckh, tckl, tsdh; - unsigned int i, ret, data, prescale, inc, int_bitrate, filt; + unsigned int i, data, prescale, inc, int_bitrate, filt; struct img_i2c_timings timing; u32 rev; + int ret; - ret = clk_prepare_enable(i2c->scb_clk); - if (ret) + ret = pm_runtime_get_sync(i2c->adap.dev.parent); + if (ret < 0) return ret; rev = img_i2c_readl(i2c, SCB_CORE_REV_REG); @@ -1163,7 +1171,8 @@ static int img_i2c_init(struct img_i2c *i2c) "Unknown hardware revision (%d.%d.%d.%d)\n", (rev >> 24) & 0xff, (rev >> 16) & 0xff, (rev >> 8) & 0xff, rev & 0xff); - clk_disable_unprepare(i2c->scb_clk); + pm_runtime_mark_last_busy(i2c->adap.dev.parent); + pm_runtime_put_autosuspend(i2c->adap.dev.parent); return -EINVAL; } @@ -1314,7 +1323,8 @@ static int img_i2c_init(struct img_i2c *i2c) /* Perform a synchronous sequence to reset the bus */ ret = img_i2c_reset_bus(i2c); - clk_disable_unprepare(i2c->scb_clk); + pm_runtime_mark_last_busy(i2c->adap.dev.parent); + pm_runtime_put_autosuspend(i2c->adap.dev.parent); return ret; } @@ -1362,8 +1372,7 @@ static int img_i2c_probe(struct platform_device *pdev) } /* Set up the exception check timer */ - setup_timer(&i2c->check_timer, img_i2c_check_timer, - (unsigned long)i2c); + timer_setup(&i2c->check_timer, img_i2c_check_timer, 0); i2c->bitrate = timings[0].max_bitrate; if (!of_property_read_u32(node, "clock-frequency", &val)) @@ -1384,22 +1393,30 @@ static int img_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); - ret = clk_prepare_enable(i2c->sys_clk); - if (ret) - return ret; + pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = img_i2c_runtime_resume(&pdev->dev); + if (ret) + return ret; + } ret = img_i2c_init(i2c); if (ret) - goto disable_clk; + goto rpm_disable; ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) - goto disable_clk; + goto rpm_disable; return 0; -disable_clk: - clk_disable_unprepare(i2c->sys_clk); +rpm_disable: + if (!pm_runtime_enabled(&pdev->dev)) + img_i2c_runtime_suspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); return ret; } @@ -1408,20 +1425,56 @@ static int img_i2c_remove(struct platform_device *dev) struct img_i2c *i2c = platform_get_drvdata(dev); i2c_del_adapter(&i2c->adap); + pm_runtime_disable(&dev->dev); + if (!pm_runtime_status_suspended(&dev->dev)) + img_i2c_runtime_suspend(&dev->dev); + + return 0; +} + +static int img_i2c_runtime_suspend(struct device *dev) +{ + struct img_i2c *i2c = dev_get_drvdata(dev); + + clk_disable_unprepare(i2c->scb_clk); clk_disable_unprepare(i2c->sys_clk); return 0; } +static int img_i2c_runtime_resume(struct device *dev) +{ + struct img_i2c *i2c = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(i2c->sys_clk); + if (ret) { + dev_err(dev, "Unable to enable sys clock\n"); + return ret; + } + + ret = clk_prepare_enable(i2c->scb_clk); + if (ret) { + dev_err(dev, "Unable to enable scb clock\n"); + clk_disable_unprepare(i2c->sys_clk); + return ret; + } + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int img_i2c_suspend(struct device *dev) { struct img_i2c *i2c = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; img_i2c_switch_mode(i2c, MODE_SUSPEND); - clk_disable_unprepare(i2c->sys_clk); - return 0; } @@ -1430,7 +1483,7 @@ static int img_i2c_resume(struct device *dev) struct img_i2c *i2c = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(i2c->sys_clk); + ret = pm_runtime_force_resume(dev); if (ret) return ret; @@ -1440,7 +1493,12 @@ static int img_i2c_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -static SIMPLE_DEV_PM_OPS(img_i2c_pm, img_i2c_suspend, img_i2c_resume); +static const struct dev_pm_ops img_i2c_pm = { + SET_RUNTIME_PM_OPS(img_i2c_runtime_suspend, + img_i2c_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(img_i2c_suspend, img_i2c_resume) +}; static const struct of_device_id img_scb_i2c_match[] = { { .compatible = "img,scb-i2c" }, diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 96caf378b1dc..950a9d74f54d 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -322,7 +322,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = { static u32 mpc_i2c_get_sec_cfg_8xxx(void) { - struct device_node *node = NULL; + struct device_node *node; u32 __iomem *reg; u32 val = 0; @@ -700,7 +700,7 @@ static int fsl_i2c_probe(struct platform_device *op) } } - if (of_get_property(op->dev.of_node, "fsl,preserve-clocking", NULL)) { + if (of_property_read_bool(op->dev.of_node, "fsl,preserve-clocking")) { clock = MPC_I2C_CLOCK_PRESERVE; } else { prop = of_get_property(op->dev.of_node, "clock-frequency", diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 23c2ea2baedc..b9172f08fd05 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -486,6 +486,22 @@ static int omap_i2c_init(struct omap_i2c_dev *omap) return 0; } +/* + * Try bus recovery, but only if SDA is actually low. + */ +static int omap_i2c_recover_bus(struct omap_i2c_dev *omap) +{ + u16 systest; + + systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG); + if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) && + (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC)) + return 0; /* bus seems to already be fine */ + if (!(systest & OMAP_I2C_SYSTEST_SCL_I_FUNC)) + return -EBUSY; /* recovery would not fix SCL */ + return i2c_recover_bus(&omap->adapter); +} + /* * Waiting on Bus Busy */ @@ -496,7 +512,7 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap) timeout = jiffies + OMAP_I2C_TIMEOUT; while (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) { if (time_after(jiffies, timeout)) - return i2c_recover_bus(&omap->adapter); + return omap_i2c_recover_bus(omap); msleep(1); } @@ -577,8 +593,13 @@ static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *omap) } if (time_after(jiffies, timeout)) { + /* + * SDA or SCL were low for the entire timeout without + * any activity detected. Most likely, a slave is + * locking up the bus with no master driving the clock. + */ dev_warn(omap->dev, "timeout waiting for bus ready\n"); - return -ETIMEDOUT; + return omap_i2c_recover_bus(omap); } msleep(1); diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index faa8fb8f2b8f..fa41ff799533 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -123,7 +123,6 @@ static struct i2c_adapter parport_adapter = { /* SMBus alert support */ static struct i2c_smbus_alert_setup alert_data = { - .alert_edge_triggered = 1, }; static struct i2c_client *ara; static struct lineop parport_ctrl_irq = { diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index a8e54df4aed6..319209a07353 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -237,7 +237,6 @@ static void i2c_parport_attach(struct parport *port) /* Setup SMBus alert if supported */ if (adapter_parm[type].smbus_alert) { - adapter->alert_data.alert_edge_triggered = 1; adapter->ara = i2c_setup_smbus_alert(&adapter->adapter, &adapter->alert_data); if (adapter->ara) diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 42d6b3a226f8..a542041df0cd 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -112,7 +112,6 @@ static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) jiffies, expires); timer->expires = jiffies + expires; - timer->data = (unsigned long)alg_data; add_timer(timer); } @@ -435,9 +434,9 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void i2c_pnx_timeout(unsigned long data) +static void i2c_pnx_timeout(struct timer_list *t) { - struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data; + struct i2c_pnx_algo_data *alg_data = from_timer(alg_data, t, mif.timer); u32 ctl; dev_err(&alg_data->adapter.dev, @@ -659,8 +658,7 @@ static int i2c_pnx_probe(struct platform_device *pdev) if (IS_ERR(alg_data->clk)) return PTR_ERR(alg_data->clk); - setup_timer(&alg_data->mif.timer, i2c_pnx_timeout, - (unsigned long)alg_data); + timer_setup(&alg_data->mif.timer, i2c_pnx_timeout, 0); snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name), "%s", pdev->name); diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index c811af4c8d81..95c2f1ce3cad 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -84,12 +84,7 @@ #define ICSR2_NACKF 0x10 -/* ICBRx (@ PCLK 33MHz) */ #define ICBR_RESERVED 0xe0 /* Should be 1 on writes */ -#define ICBRL_SP100K (19 | ICBR_RESERVED) -#define ICBRH_SP100K (16 | ICBR_RESERVED) -#define ICBRL_SP400K (21 | ICBR_RESERVED) -#define ICBRH_SP400K (9 | ICBR_RESERVED) #define RIIC_INIT_MSG -1 @@ -288,48 +283,99 @@ static const struct i2c_algorithm riic_algo = { .functionality = riic_func, }; -static int riic_init_hw(struct riic_dev *riic, u32 spd) +static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t) { int ret; unsigned long rate; + int total_ticks, cks, brl, brh; ret = clk_prepare_enable(riic->clk); if (ret) return ret; - /* - * TODO: Implement formula to calculate the timing values depending on - * variable parent clock rate and arbitrary bus speed - */ - rate = clk_get_rate(riic->clk); - if (rate != 33325000) { + if (t->bus_freq_hz > 400000) { dev_err(&riic->adapter.dev, - "invalid parent clk (%lu). Must be 33325000Hz\n", rate); + "unsupported bus speed (%dHz). 400000 max\n", + t->bus_freq_hz); clk_disable_unprepare(riic->clk); return -EINVAL; } + rate = clk_get_rate(riic->clk); + + /* + * Assume the default register settings: + * FER.SCLE = 1 (SCL sync circuit enabled, adds 2 or 3 cycles) + * FER.NFE = 1 (noise circuit enabled) + * MR3.NF = 0 (1 cycle of noise filtered out) + * + * Freq (CKS=000) = (I2CCLK + tr + tf)/ (BRH + 3 + 1) + (BRL + 3 + 1) + * Freq (CKS!=000) = (I2CCLK + tr + tf)/ (BRH + 2 + 1) + (BRL + 2 + 1) + */ + + /* + * Determine reference clock rate. We must be able to get the desired + * frequency with only 62 clock ticks max (31 high, 31 low). + * Aim for a duty of 60% LOW, 40% HIGH. + */ + total_ticks = DIV_ROUND_UP(rate, t->bus_freq_hz); + + for (cks = 0; cks < 7; cks++) { + /* + * 60% low time must be less than BRL + 2 + 1 + * BRL max register value is 0x1F. + */ + brl = ((total_ticks * 6) / 10); + if (brl <= (0x1F + 3)) + break; + + total_ticks /= 2; + rate /= 2; + } + + if (brl > (0x1F + 3)) { + dev_err(&riic->adapter.dev, "invalid speed (%lu). Too slow.\n", + (unsigned long)t->bus_freq_hz); + clk_disable_unprepare(riic->clk); + return -EINVAL; + } + + brh = total_ticks - brl; + + /* Remove automatic clock ticks for sync circuit and NF */ + if (cks == 0) { + brl -= 4; + brh -= 4; + } else { + brl -= 3; + brh -= 3; + } + + /* + * Remove clock ticks for rise and fall times. Convert ns to clock + * ticks. + */ + brl -= t->scl_fall_ns / (1000000000 / rate); + brh -= t->scl_rise_ns / (1000000000 / rate); + + /* Adjust for min register values for when SCLE=1 and NFE=1 */ + if (brl < 1) + brl = 1; + if (brh < 1) + brh = 1; + + pr_debug("i2c-riic: freq=%lu, duty=%d, fall=%lu, rise=%lu, cks=%d, brl=%d, brh=%d\n", + rate / total_ticks, ((brl + 3) * 100) / (brl + brh + 6), + t->scl_fall_ns / (1000000000 / rate), + t->scl_rise_ns / (1000000000 / rate), cks, brl, brh); + /* Changing the order of accessing IICRST and ICE may break things! */ writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1); riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1); - switch (spd) { - case 100000: - writeb(ICMR1_CKS(3), riic->base + RIIC_ICMR1); - writeb(ICBRH_SP100K, riic->base + RIIC_ICBRH); - writeb(ICBRL_SP100K, riic->base + RIIC_ICBRL); - break; - case 400000: - writeb(ICMR1_CKS(1), riic->base + RIIC_ICMR1); - writeb(ICBRH_SP400K, riic->base + RIIC_ICBRH); - writeb(ICBRL_SP400K, riic->base + RIIC_ICBRL); - break; - default: - dev_err(&riic->adapter.dev, - "unsupported bus speed (%dHz). Use 100000 or 400000\n", spd); - clk_disable_unprepare(riic->clk); - return -EINVAL; - } + writeb(ICMR1_CKS(cks), riic->base + RIIC_ICMR1); + writeb(brh | ICBR_RESERVED, riic->base + RIIC_ICBRH); + writeb(brl | ICBR_RESERVED, riic->base + RIIC_ICBRL); writeb(0, riic->base + RIIC_ICSER); writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3); @@ -351,11 +397,10 @@ static struct riic_irq_desc riic_irqs[] = { static int riic_i2c_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct riic_dev *riic; struct i2c_adapter *adap; struct resource *res; - u32 bus_rate = 0; + struct i2c_timings i2c_t; int i, ret; riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL); @@ -396,8 +441,9 @@ static int riic_i2c_probe(struct platform_device *pdev) init_completion(&riic->msg_done); - of_property_read_u32(np, "clock-frequency", &bus_rate); - ret = riic_init_hw(riic, bus_rate); + i2c_parse_fw_timings(&pdev->dev, &i2c_t, true); + + ret = riic_init_hw(riic, &i2c_t); if (ret) return ret; @@ -408,7 +454,8 @@ static int riic_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, riic); - dev_info(&pdev->dev, "registered with %dHz bus speed\n", bus_rate); + dev_info(&pdev->dev, "registered with %dHz bus speed\n", + i2c_t.bus_freq_hz); return 0; } diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 6f2aaeb7c4fa..c03acdf71397 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -881,7 +881,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; struct resource *res; - const struct of_device_id *match; + const struct sh_mobile_dt_config *config; int ret; u32 bus_speed; @@ -913,10 +913,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) pd->bus_speed = ret ? STANDARD_MODE : bus_speed; pd->clks_per_count = 1; - match = of_match_device(sh_mobile_i2c_dt_ids, &dev->dev); - if (match) { - const struct sh_mobile_dt_config *config = match->data; - + config = of_device_get_match_data(&dev->dev); + if (config) { pd->clks_per_count = config->clks_per_count; if (config->setup) diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c index addd90a8cb59..7c7fc01116a1 100644 --- a/drivers/i2c/busses/i2c-taos-evm.c +++ b/drivers/i2c/busses/i2c-taos-evm.c @@ -282,8 +282,7 @@ static void taos_disconnect(struct serio *serio) { struct taos_data *taos = serio_get_drvdata(serio); - if (taos->client) - i2c_unregister_device(taos->client); + i2c_unregister_device(taos->client); i2c_del_adapter(&taos->adapter); serio_close(serio); kfree(taos); diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c index df0976f4432a..19f8eec38717 100644 --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -118,8 +118,6 @@ static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk) static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c, struct device_node *node) { - u32 type; - if (!node) return -EINVAL; @@ -127,10 +125,6 @@ static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c, if (!i2c->alert_data.irq) return -EINVAL; - type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq)); - i2c->alert_data.alert_edge_triggered = - (type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0; - i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data); if (!i2c->ara) return -ENODEV; @@ -149,8 +143,7 @@ static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c, static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c) { - if (i2c->ara) - i2c_unregister_device(i2c->ara); + i2c_unregister_device(i2c->ara); } static int thunder_i2c_probe_pci(struct pci_dev *pdev, diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index 7e89ba6fcf6f..a7ac746018ad 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -129,6 +129,11 @@ struct slimpro_i2c_dev { #define to_slimpro_i2c_dev(cl) \ container_of(cl, struct slimpro_i2c_dev, mbox_client) +enum slimpro_i2c_version { + XGENE_SLIMPRO_I2C_V1 = 0, + XGENE_SLIMPRO_I2C_V2 = 1, +}; + /* * This function tests and clears a bitmask then returns its old value */ @@ -476,6 +481,15 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) } } else { struct acpi_pcct_hw_reduced *cppc_ss; + const struct acpi_device_id *acpi_id; + int version = XGENE_SLIMPRO_I2C_V1; + + acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table, + &pdev->dev); + if (!acpi_id) + return -EINVAL; + + version = (int)acpi_id->driver_data; if (device_property_read_u32(&pdev->dev, "pcc-channel", &ctx->mbox_idx)) @@ -514,9 +528,16 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) */ ctx->comm_base_addr = cppc_ss->base_address; if (ctx->comm_base_addr) { - ctx->pcc_comm_addr = memremap(ctx->comm_base_addr, - cppc_ss->length, - MEMREMAP_WB); + if (version == XGENE_SLIMPRO_I2C_V2) + ctx->pcc_comm_addr = memremap( + ctx->comm_base_addr, + cppc_ss->length, + MEMREMAP_WT); + else + ctx->pcc_comm_addr = memremap( + ctx->comm_base_addr, + cppc_ss->length, + MEMREMAP_WB); } else { dev_err(&pdev->dev, "Failed to get PCC comm region\n"); rc = -ENOENT; @@ -581,7 +602,8 @@ MODULE_DEVICE_TABLE(of, xgene_slimpro_i2c_dt_ids); #ifdef CONFIG_ACPI static const struct acpi_device_id xgene_slimpro_i2c_acpi_ids[] = { - {"APMC0D40", 0}, + {"APMC0D40", XGENE_SLIMPRO_I2C_V1}, + {"APMC0D8B", XGENE_SLIMPRO_I2C_V2}, {} }; MODULE_DEVICE_TABLE(acpi, xgene_slimpro_i2c_acpi_ids); diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 6b106e94bc09..b970bf8f38e5 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -81,9 +82,12 @@ struct xlp9xx_i2c_dev { struct completion msg_complete; int irq; bool msg_read; + bool len_recv; + bool client_pec; u32 __iomem *base; u32 msg_buf_remaining; u32 msg_len; + u32 ip_clk_hz; u32 clk_hz; u32 msg_err; u8 *msg_buf; @@ -141,10 +145,25 @@ static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv) static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) { u32 len, i; - u8 *buf = priv->msg_buf; + u8 rlen, *buf = priv->msg_buf; len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & XLP9XX_I2C_FIFO_WCNT_MASK; + if (!len) + return; + if (priv->len_recv) { + /* read length byte */ + rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); + *buf++ = rlen; + len--; + if (priv->client_pec) + ++rlen; + /* update remaining bytes and message length */ + priv->msg_buf_remaining = rlen; + priv->msg_len = rlen + 1; + priv->len_recv = false; + } + len = min(priv->msg_buf_remaining, len); for (i = 0; i < len; i++, buf++) *buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); @@ -213,7 +232,7 @@ static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv) * The controller uses 5 * SCL clock internally. * So prescale value should be divided by 5. */ - prescale = DIV_ROUND_UP(XLP9XX_I2C_IP_CLK_FREQ, priv->clk_hz); + prescale = DIV_ROUND_UP(priv->ip_clk_hz, priv->clk_hz); prescale = ((prescale - 8) / 5) - 1; xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST); xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN | @@ -228,7 +247,7 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, int last_msg) { unsigned long timeleft; - u32 intr_mask, cmd, val; + u32 intr_mask, cmd, val, len; priv->msg_buf = msg->buf; priv->msg_buf_remaining = priv->msg_len = msg->len; @@ -261,9 +280,13 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, else val &= ~XLP9XX_I2C_CTRL_ADDMODE; + priv->len_recv = msg->flags & I2C_M_RECV_LEN; + len = priv->len_recv ? XLP9XX_I2C_FIFO_SIZE : msg->len; + priv->client_pec = msg->flags & I2C_CLIENT_PEC; + /* set data length to be transferred */ val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | - (msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); + (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); /* fill fifo during tx */ @@ -310,6 +333,9 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, return -ETIMEDOUT; } + /* update msg->len with actual received length */ + if (msg->flags & I2C_M_RECV_LEN) + msg->len = priv->msg_len; return 0; } @@ -342,9 +368,19 @@ static const struct i2c_algorithm xlp9xx_i2c_algo = { static int xlp9xx_i2c_get_frequency(struct platform_device *pdev, struct xlp9xx_i2c_dev *priv) { + struct clk *clk; u32 freq; int err; + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + priv->ip_clk_hz = XLP9XX_I2C_IP_CLK_FREQ; + dev_dbg(&pdev->dev, "using default input frequency %u\n", + priv->ip_clk_hz); + } else { + priv->ip_clk_hz = clk_get_rate(clk); + } + err = device_property_read_u32(&pdev->dev, "clock-frequency", &freq); if (err) { freq = XLP9XX_I2C_DEFAULT_FREQ; diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 56e46581b84b..706164b4c5be 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -205,9 +206,6 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) */ while (i++ < RECOVERY_CLK_CNT * 2) { if (val) { - /* Break if SDA is high */ - if (bri->get_sda && bri->get_sda(adap)) - break; /* SCL shouldn't be low here */ if (!bri->get_scl(adap)) { dev_err(&adap->dev, @@ -215,6 +213,9 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) ret = -EBUSY; break; } + /* Break if SDA is high */ + if (bri->get_sda && bri->get_sda(adap)) + break; } val = !val; @@ -222,6 +223,10 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) ndelay(RECOVERY_NDELAY); } + /* check if recovery actually succeeded */ + if (bri->get_sda && !bri->get_sda(adap)) + ret = -EBUSY; + if (bri->unprepare_recovery) bri->unprepare_recovery(adap); @@ -666,10 +671,16 @@ static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter, } static void i2c_dev_set_name(struct i2c_adapter *adap, - struct i2c_client *client) + struct i2c_client *client, + struct i2c_board_info const *info) { struct acpi_device *adev = ACPI_COMPANION(&client->dev); + if (info && info->dev_name) { + dev_set_name(&client->dev, "i2c-%s", info->dev_name); + return; + } + if (adev) { dev_set_name(&client->dev, "i2c-%s", acpi_dev_name(adev)); return; @@ -766,7 +777,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.of_node = info->of_node; client->dev.fwnode = info->fwnode; - i2c_dev_set_name(adap, client); + i2c_dev_set_name(adap, client, info); if (info->properties) { status = device_add_properties(&client->dev, info->properties); @@ -808,6 +819,8 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { + if (!client) + return; if (client->dev.of_node) of_node_clear_flag(client->dev.of_node, OF_POPULATED); if (ACPI_COMPANION(&client->dev)) @@ -1259,6 +1272,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap) goto out_list; } + res = of_i2c_setup_smbus_alert(adap); + if (res) + goto out_reg; + dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); pm_runtime_no_callbacks(&adap->dev); @@ -1290,6 +1307,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap) return 0; +out_reg: + init_completion(&adap->dev_released); + device_unregister(&adap->dev); + wait_for_completion(&adap->dev_released); out_list: mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); @@ -1417,8 +1438,7 @@ static int __unregister_client(struct device *dev, void *dummy) static int __unregister_dummy(struct device *dev, void *dummy) { struct i2c_client *client = i2c_verify_client(dev); - if (client) - i2c_unregister_device(client); + i2c_unregister_device(client); return 0; } diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index 10f00a82ec9d..4bb9927afd01 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -17,6 +17,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -592,3 +593,57 @@ s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, return i; } EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data_or_emulated); + +/** + * i2c_setup_smbus_alert - Setup SMBus alert support + * @adapter: the target adapter + * @setup: setup data for the SMBus alert handler + * Context: can sleep + * + * Setup handling of the SMBus alert protocol on a given I2C bus segment. + * + * Handling can be done either through our IRQ handler, or by the + * adapter (from its handler, periodic polling, or whatever). + * + * NOTE that if we manage the IRQ, we *MUST* know if it's level or + * edge triggered in order to hand it to the workqueue correctly. + * If triggering the alert seems to wedge the system, you probably + * should have said it's level triggered. + * + * This returns the ara client, which should be saved for later use with + * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL + * to indicate an error. + */ +struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, + struct i2c_smbus_alert_setup *setup) +{ + struct i2c_board_info ara_board_info = { + I2C_BOARD_INFO("smbus_alert", 0x0c), + .platform_data = setup, + }; + + return i2c_new_device(adapter, &ara_board_info); +} +EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert); + +#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF) +int of_i2c_setup_smbus_alert(struct i2c_adapter *adapter) +{ + struct i2c_client *client; + int irq; + + irq = of_property_match_string(adapter->dev.of_node, "interrupt-names", + "smbus_alert"); + if (irq == -EINVAL || irq == -ENODATA) + return 0; + else if (irq < 0) + return irq; + + client = i2c_setup_smbus_alert(adapter, NULL); + if (!client) + return -ENODEV; + + return 0; +} +EXPORT_SYMBOL_GPL(of_i2c_setup_smbus_alert); +#endif diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index f9271c713d20..5a1dd7f13bac 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -21,12 +21,11 @@ #include #include #include +#include #include #include struct i2c_smbus_alert { - unsigned int alert_edge_triggered:1; - int irq; struct work_struct alert; struct i2c_client *ara; /* Alert response address */ }; @@ -72,13 +71,12 @@ static int smbus_do_alert(struct device *dev, void *addrp) * The alert IRQ handler needs to hand work off to a task which can issue * SMBus calls, because those sleeping calls can't be made in IRQ context. */ -static void smbus_alert(struct work_struct *work) +static irqreturn_t smbus_alert(int irq, void *d) { - struct i2c_smbus_alert *alert; + struct i2c_smbus_alert *alert = d; struct i2c_client *ara; unsigned short prev_addr = 0; /* Not a valid address */ - alert = container_of(work, struct i2c_smbus_alert, alert); ara = alert->ara; for (;;) { @@ -115,21 +113,17 @@ static void smbus_alert(struct work_struct *work) prev_addr = data.addr; } - /* We handled all alerts; re-enable level-triggered IRQs */ - if (!alert->alert_edge_triggered) - enable_irq(alert->irq); + return IRQ_HANDLED; } -static irqreturn_t smbalert_irq(int irq, void *d) +static void smbalert_work(struct work_struct *work) { - struct i2c_smbus_alert *alert = d; + struct i2c_smbus_alert *alert; - /* Disable level-triggered IRQs until we handle them */ - if (!alert->alert_edge_triggered) - disable_irq_nosync(irq); + alert = container_of(work, struct i2c_smbus_alert, alert); + + smbus_alert(0, alert); - schedule_work(&alert->alert); - return IRQ_HANDLED; } /* Setup SMBALERT# infrastructure */ @@ -139,28 +133,35 @@ static int smbalert_probe(struct i2c_client *ara, struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev); struct i2c_smbus_alert *alert; struct i2c_adapter *adapter = ara->adapter; - int res; + int res, irq; alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert), GFP_KERNEL); if (!alert) return -ENOMEM; - alert->alert_edge_triggered = setup->alert_edge_triggered; - alert->irq = setup->irq; - INIT_WORK(&alert->alert, smbus_alert); + if (setup) { + irq = setup->irq; + } else { + irq = of_irq_get_byname(adapter->dev.of_node, "smbus_alert"); + if (irq <= 0) + return irq; + } + + INIT_WORK(&alert->alert, smbalert_work); alert->ara = ara; - if (setup->irq > 0) { - res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq, - 0, "smbus_alert", alert); + if (irq > 0) { + res = devm_request_threaded_irq(&ara->dev, irq, + NULL, smbus_alert, + IRQF_SHARED | IRQF_ONESHOT, + "smbus_alert", alert); if (res) return res; } i2c_set_clientdata(ara, alert); - dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n", - setup->alert_edge_triggered ? "edge" : "level"); + dev_info(&adapter->dev, "supports SMBALERT#\n"); return 0; } @@ -189,38 +190,6 @@ static struct i2c_driver smbalert_driver = { .id_table = smbalert_ids, }; -/** - * i2c_setup_smbus_alert - Setup SMBus alert support - * @adapter: the target adapter - * @setup: setup data for the SMBus alert handler - * Context: can sleep - * - * Setup handling of the SMBus alert protocol on a given I2C bus segment. - * - * Handling can be done either through our IRQ handler, or by the - * adapter (from its handler, periodic polling, or whatever). - * - * NOTE that if we manage the IRQ, we *MUST* know if it's level or - * edge triggered in order to hand it to the workqueue correctly. - * If triggering the alert seems to wedge the system, you probably - * should have said it's level triggered. - * - * This returns the ara client, which should be saved for later use with - * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL - * to indicate an error. - */ -struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, - struct i2c_smbus_alert_setup *setup) -{ - struct i2c_board_info ara_board_info = { - I2C_BOARD_INFO("smbus_alert", 0x0c), - .platform_data = setup, - }; - - return i2c_new_device(adapter, &ara_board_info); -} -EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert); - /** * i2c_handle_smbus_alert - Handle an SMBus alert * @ara: the ARA client on the relevant adapter diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 7b992db38021..2ca068d8b92d 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -246,36 +246,6 @@ static irqreturn_t pca954x_irq_handler(int irq, void *dev_id) return handled ? IRQ_HANDLED : IRQ_NONE; } -static void pca954x_irq_mask(struct irq_data *idata) -{ - struct pca954x *data = irq_data_get_irq_chip_data(idata); - unsigned int pos = idata->hwirq; - unsigned long flags; - - raw_spin_lock_irqsave(&data->lock, flags); - - data->irq_mask &= ~BIT(pos); - if (!data->irq_mask) - disable_irq(data->client->irq); - - raw_spin_unlock_irqrestore(&data->lock, flags); -} - -static void pca954x_irq_unmask(struct irq_data *idata) -{ - struct pca954x *data = irq_data_get_irq_chip_data(idata); - unsigned int pos = idata->hwirq; - unsigned long flags; - - raw_spin_lock_irqsave(&data->lock, flags); - - if (!data->irq_mask) - enable_irq(data->client->irq); - data->irq_mask |= BIT(pos); - - raw_spin_unlock_irqrestore(&data->lock, flags); -} - static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) { if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW) @@ -285,8 +255,6 @@ static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) static struct irq_chip pca954x_irq_chip = { .name = "i2c-mux-pca954x", - .irq_mask = pca954x_irq_mask, - .irq_unmask = pca954x_irq_unmask, .irq_set_type = pca954x_irq_set_type, }; @@ -294,7 +262,7 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc) { struct pca954x *data = i2c_mux_priv(muxc); struct i2c_client *client = data->client; - int c, err, irq; + int c, irq; if (!data->chip->has_irq || client->irq <= 0) return 0; @@ -309,29 +277,31 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc) for (c = 0; c < data->chip->nchans; c++) { irq = irq_create_mapping(data->irq, c); + if (!irq) { + dev_err(&client->dev, "failed irq create map\n"); + return -EINVAL; + } irq_set_chip_data(irq, data); irq_set_chip_and_handler(irq, &pca954x_irq_chip, handle_simple_irq); } - err = devm_request_threaded_irq(&client->dev, data->client->irq, NULL, - pca954x_irq_handler, - IRQF_ONESHOT | IRQF_SHARED, - "pca954x", data); - if (err) - goto err_req_irq; - - disable_irq(data->client->irq); - return 0; -err_req_irq: - for (c = 0; c < data->chip->nchans; c++) { - irq = irq_find_mapping(data->irq, c); - irq_dispose_mapping(irq); - } - irq_domain_remove(data->irq); +} - return err; +static void pca954x_cleanup(struct i2c_mux_core *muxc) +{ + struct pca954x *data = i2c_mux_priv(muxc); + int c, irq; + + if (data->irq) { + for (c = 0; c < data->chip->nchans; c++) { + irq = irq_find_mapping(data->irq, c); + irq_dispose_mapping(irq); + } + irq_domain_remove(data->irq); + } + i2c_mux_del_adapters(muxc); } /* @@ -391,7 +361,7 @@ static int pca954x_probe(struct i2c_client *client, ret = pca954x_irq_setup(muxc); if (ret) - goto fail_del_adapters; + goto fail_cleanup; /* Now create an adapter for each channel */ for (num = 0; num < data->chip->nchans; num++) { @@ -414,7 +384,16 @@ static int pca954x_probe(struct i2c_client *client, ret = i2c_mux_add_adapter(muxc, force, num, class); if (ret) - goto fail_del_adapters; + goto fail_cleanup; + } + + if (data->irq) { + ret = devm_request_threaded_irq(&client->dev, data->client->irq, + NULL, pca954x_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + "pca954x", data); + if (ret) + goto fail_cleanup; } dev_info(&client->dev, @@ -424,26 +403,16 @@ static int pca954x_probe(struct i2c_client *client, return 0; -fail_del_adapters: - i2c_mux_del_adapters(muxc); +fail_cleanup: + pca954x_cleanup(muxc); return ret; } static int pca954x_remove(struct i2c_client *client) { struct i2c_mux_core *muxc = i2c_get_clientdata(client); - struct pca954x *data = i2c_mux_priv(muxc); - int c, irq; - if (data->irq) { - for (c = 0; c < data->chip->nchans; c++) { - irq = irq_find_mapping(data->irq, c); - irq_dispose_mapping(irq); - } - irq_domain_remove(data->irq); - } - - i2c_mux_del_adapters(muxc); + pca954x_cleanup(muxc); return 0; } diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index d97031804de8..f6c9c3dc6cad 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -107,9 +107,9 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, put_device(&adapter->dev); mux->data.n_values = of_get_child_count(np); - if (of_find_property(np, "little-endian", NULL)) { + if (of_property_read_bool(np, "little-endian")) { mux->data.little_endian = true; - } else if (of_find_property(np, "big-endian", NULL)) { + } else if (of_property_read_bool(np, "big-endian")) { mux->data.little_endian = false; } else { #if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : \ @@ -122,10 +122,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, #error Endianness not defined? #endif } - if (of_find_property(np, "write-only", NULL)) - mux->data.write_only = true; - else - mux->data.write_only = false; + mux->data.write_only = of_property_read_bool(np, "write-only"); values = devm_kzalloc(&pdev->dev, sizeof(*mux->data.values) * mux->data.n_values, diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h index 694116630ffa..865bbeaaf00c 100644 --- a/drivers/mfd/intel-lpss.h +++ b/drivers/mfd/intel-lpss.h @@ -38,12 +38,7 @@ int intel_lpss_resume(struct device *dev); #ifdef CONFIG_PM_SLEEP #define INTEL_LPSS_SLEEP_PM_OPS \ .prepare = intel_lpss_prepare, \ - .suspend = intel_lpss_suspend, \ - .resume = intel_lpss_resume, \ - .freeze = intel_lpss_suspend, \ - .thaw = intel_lpss_resume, \ - .poweroff = intel_lpss_suspend, \ - .restore = intel_lpss_resume, + SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_lpss_suspend, intel_lpss_resume) #else #define INTEL_LPSS_SLEEP_PM_OPS #endif diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 40534352e574..ad774161a22d 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -1107,14 +1108,6 @@ static void sm501_gpio_remove(struct sm501_devdata *sm) kfree(gpio->regs_res); } -static inline int sm501_gpio_pin2nr(struct sm501_devdata *sm, unsigned int pin) -{ - struct sm501_gpio *gpio = &sm->gpio; - int base = (pin < 32) ? gpio->low.gpio.base : gpio->high.gpio.base; - - return (pin % 32) + base; -} - static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) { return sm->gpio.registered; @@ -1129,11 +1122,6 @@ static inline void sm501_gpio_remove(struct sm501_devdata *sm) { } -static inline int sm501_gpio_pin2nr(struct sm501_devdata *sm, unsigned int pin) -{ - return -1; -} - static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) { return 0; @@ -1145,20 +1133,37 @@ static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, { struct i2c_gpio_platform_data *icd; struct platform_device *pdev; + struct gpiod_lookup_table *lookup; pdev = sm501_create_subdev(sm, "i2c-gpio", 0, sizeof(struct i2c_gpio_platform_data)); if (!pdev) return -ENOMEM; + /* Create a gpiod lookup using gpiochip-local offsets */ + lookup = devm_kzalloc(&pdev->dev, + sizeof(*lookup) + 3 * sizeof(struct gpiod_lookup), + GFP_KERNEL); + lookup->dev_id = "i2c-gpio"; + if (iic->pin_sda < 32) + lookup->table[0].chip_label = "SM501-LOW"; + else + lookup->table[0].chip_label = "SM501-HIGH"; + lookup->table[0].chip_hwnum = iic->pin_sda % 32; + lookup->table[0].con_id = NULL; + lookup->table[0].idx = 0; + lookup->table[0].flags = GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN; + if (iic->pin_scl < 32) + lookup->table[1].chip_label = "SM501-LOW"; + else + lookup->table[1].chip_label = "SM501-HIGH"; + lookup->table[1].chip_hwnum = iic->pin_scl % 32; + lookup->table[1].con_id = NULL; + lookup->table[1].idx = 1; + lookup->table[1].flags = GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN; + gpiod_add_lookup_table(lookup); + icd = dev_get_platdata(&pdev->dev); - - /* We keep the pin_sda and pin_scl fields relative in case the - * same platform data is passed to >1 SM501. - */ - - icd->sda_pin = sm501_gpio_pin2nr(sm, iic->pin_sda); - icd->scl_pin = sm501_gpio_pin2nr(sm, iic->pin_scl); icd->timeout = iic->timeout; icd->udelay = iic->udelay; @@ -1170,9 +1175,9 @@ static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, pdev->id = iic->bus_num; - dev_info(sm->dev, "registering i2c-%d: sda=%d (%d), scl=%d (%d)\n", + dev_info(sm->dev, "registering i2c-%d: sda=%d, scl=%d\n", iic->bus_num, - icd->sda_pin, iic->pin_sda, icd->scl_pin, iic->pin_scl); + iic->pin_sda, iic->pin_scl); return sm501_register_device(sm, pdev); } diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 764ff5df0dbc..e0b4b36ef010 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include /* * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. @@ -175,6 +177,64 @@ static const struct i2c_device_id at24_ids[] = { }; MODULE_DEVICE_TABLE(i2c, at24_ids); +static const struct of_device_id at24_of_match[] = { + { + .compatible = "atmel,24c00", + .data = (void *)AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) + }, + { + .compatible = "atmel,24c01", + .data = (void *)AT24_DEVICE_MAGIC(1024 / 8, 0) + }, + { + .compatible = "atmel,24c02", + .data = (void *)AT24_DEVICE_MAGIC(2048 / 8, 0) + }, + { + .compatible = "atmel,spd", + .data = (void *)AT24_DEVICE_MAGIC(2048 / 8, + AT24_FLAG_READONLY | AT24_FLAG_IRUGO) + }, + { + .compatible = "atmel,24c04", + .data = (void *)AT24_DEVICE_MAGIC(4096 / 8, 0) + }, + { + .compatible = "atmel,24c08", + .data = (void *)AT24_DEVICE_MAGIC(8192 / 8, 0) + }, + { + .compatible = "atmel,24c16", + .data = (void *)AT24_DEVICE_MAGIC(16384 / 8, 0) + }, + { + .compatible = "atmel,24c32", + .data = (void *)AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) + }, + { + .compatible = "atmel,24c64", + .data = (void *)AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) + }, + { + .compatible = "atmel,24c128", + .data = (void *)AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) + }, + { + .compatible = "atmel,24c256", + .data = (void *)AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) + }, + { + .compatible = "atmel,24c512", + .data = (void *)AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) + }, + { + .compatible = "atmel,24c1024", + .data = (void *)AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) + }, + { }, +}; +MODULE_DEVICE_TABLE(of, at24_of_match); + static const struct acpi_device_id at24_acpi_ids[] = { { "INT3499", AT24_DEVICE_MAGIC(8192 / 8, 0) }, { } @@ -501,11 +561,21 @@ static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf, static int at24_read(void *priv, unsigned int off, void *val, size_t count) { struct at24_data *at24 = priv; + struct i2c_client *client; char *buf = val; + int ret; if (unlikely(!count)) return count; + client = at24_translate_offset(at24, &off); + + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + return ret; + } + /* * Read data from chip, protecting against concurrent updates * from this host, but not from other I2C masters. @@ -518,6 +588,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count) status = at24->read_func(at24, buf, off, count); if (status < 0) { mutex_unlock(&at24->lock); + pm_runtime_put(&client->dev); return status; } buf += status; @@ -527,17 +598,29 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count) mutex_unlock(&at24->lock); + pm_runtime_put(&client->dev); + return 0; } static int at24_write(void *priv, unsigned int off, void *val, size_t count) { struct at24_data *at24 = priv; + struct i2c_client *client; char *buf = val; + int ret; if (unlikely(!count)) return -EINVAL; + client = at24_translate_offset(at24, &off); + + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + return ret; + } + /* * Write data to chip, protecting against concurrent updates * from this host, but not from other I2C masters. @@ -550,6 +633,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) status = at24->write_func(at24, buf, off, count); if (status < 0) { mutex_unlock(&at24->lock); + pm_runtime_put(&client->dev); return status; } buf += status; @@ -559,6 +643,8 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) mutex_unlock(&at24->lock); + pm_runtime_put(&client->dev); + return 0; } @@ -570,6 +656,10 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip) if (device_property_present(dev, "read-only")) chip->flags |= AT24_FLAG_READONLY; + err = device_property_read_u32(dev, "size", &val); + if (!err) + chip->byte_len = val; + err = device_property_read_u32(dev, "pagesize", &val); if (!err) { chip->page_size = val; @@ -598,7 +688,16 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) if (client->dev.platform_data) { chip = *(struct at24_platform_data *)client->dev.platform_data; } else { - if (id) { + /* + * The I2C core allows OF nodes compatibles to match against the + * I2C device ID table as a fallback, so check not only if an OF + * node is present but also if it matches an OF device ID entry. + */ + if (client->dev.of_node && + of_match_device(at24_of_match, &client->dev)) { + magic = (kernel_ulong_t) + of_device_get_match_data(&client->dev); + } else if (id) { magic = id->driver_data; } else { const struct acpi_device_id *aid; @@ -739,11 +838,16 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) i2c_set_clientdata(client, at24); + /* enable runtime pm */ + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + /* * Perform a one-byte test read to verify that the * chip is functional. */ err = at24_read(at24, 0, &test_byte, 1); + pm_runtime_idle(&client->dev); if (err) { err = -ENODEV; goto err_clients; @@ -791,6 +895,8 @@ err_clients: if (at24->client[i]) i2c_unregister_device(at24->client[i]); + pm_runtime_disable(&client->dev); + return err; } @@ -806,6 +912,9 @@ static int at24_remove(struct i2c_client *client) for (i = 1; i < at24->num_addresses; i++) i2c_unregister_device(at24->client[i]); + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + return 0; } @@ -814,6 +923,7 @@ static int at24_remove(struct i2c_client *client) static struct i2c_driver at24_driver = { .driver = { .name = "at24", + .of_match_table = at24_of_match, .acpi_match_table = ACPI_PTR(at24_acpi_ids), }, .probe = at24_probe, diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 5ab90c1f3f7c..fbca0ba7fc52 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -184,6 +184,20 @@ config CHARGER_SBS help Say Y to include support for SBS compilant battery chargers. +config MANAGER_SBS + tristate "Smart Battery System Manager" + depends on I2C && I2C_MUX && GPIOLIB + select I2C_SMBUS + help + Say Y here to include support for Smart Battery System Manager + ICs. The driver reports online and charging status via sysfs. + It presents itself also as I2C mux which allows to bind + smart battery driver to its ports. + Supported is for example LTC1760. + + This driver can also be built as a module. If so, the module will be + called sbs-manager. + config BATTERY_BQ27XXX tristate "BQ27xxx battery driver" help diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index aae4e4a8bbb3..e83aa843bcc6 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o obj-$(CONFIG_CHARGER_SBS) += sbs-charger.o +obj-$(CONFIG_MANAGER_SBS) += sbs-manager.o obj-$(CONFIG_BATTERY_BQ27XXX) += bq27xxx_battery.o obj-$(CONFIG_BATTERY_BQ27XXX_I2C) += bq27xxx_battery_i2c.o obj-$(CONFIG_BATTERY_BQ27XXX_HDQ) += bq27xxx_battery_hdq.o diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index b19a73176910..83d7b4115857 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -177,10 +177,8 @@ static bool force_load; static int sbs_read_word_data(struct i2c_client *client, u8 address) { struct sbs_info *chip = i2c_get_clientdata(client); + int retries = chip->i2c_retry_count; s32 ret = 0; - int retries = 1; - - retries = chip->i2c_retry_count; while (retries > 0) { ret = i2c_smbus_read_word_data(client, address); @@ -204,7 +202,7 @@ static int sbs_read_string_data(struct i2c_client *client, u8 address, { struct sbs_info *chip = i2c_get_clientdata(client); s32 ret = 0, block_length = 0; - int retries_length = 1, retries_block = 1; + int retries_length, retries_block; u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; retries_length = chip->i2c_retry_count; @@ -269,10 +267,8 @@ static int sbs_write_word_data(struct i2c_client *client, u8 address, u16 value) { struct sbs_info *chip = i2c_get_clientdata(client); + int retries = chip->i2c_retry_count; s32 ret = 0; - int retries = 1; - - retries = chip->i2c_retry_count; while (retries > 0) { ret = i2c_smbus_write_word_data(client, address, value); @@ -321,16 +317,6 @@ static int sbs_get_battery_presence_and_health( union power_supply_propval *val) { s32 ret; - struct sbs_info *chip = i2c_get_clientdata(client); - - if (psp == POWER_SUPPLY_PROP_PRESENT && chip->gpio_detect) { - ret = gpiod_get_value_cansleep(chip->gpio_detect); - if (ret < 0) - return ret; - val->intval = ret; - chip->is_present = val->intval; - return ret; - } /* * Write to ManufacturerAccess with ManufacturerAccess command @@ -570,7 +556,7 @@ static int sbs_get_battery_serial_number(struct i2c_client *client, if (ret < 0) return ret; - ret = sprintf(sbs_serial, "%04x", ret); + sprintf(sbs_serial, "%04x", ret); val->strval = sbs_serial; return 0; @@ -598,6 +584,19 @@ static int sbs_get_property(struct power_supply *psy, struct sbs_info *chip = power_supply_get_drvdata(psy); struct i2c_client *client = chip->client; + if (chip->gpio_detect) { + ret = gpiod_get_value_cansleep(chip->gpio_detect); + if (ret < 0) + return ret; + if (psp == POWER_SUPPLY_PROP_PRESENT) { + val->intval = ret; + chip->is_present = val->intval; + return 0; + } + if (ret == 0) + return -ENODATA; + } + switch (psp) { case POWER_SUPPLY_PROP_PRESENT: case POWER_SUPPLY_PROP_HEALTH: diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c new file mode 100644 index 000000000000..ccb4217b9638 --- /dev/null +++ b/drivers/power/supply/sbs-manager.c @@ -0,0 +1,445 @@ +/* + * Driver for SBS compliant Smart Battery System Managers + * + * The device communicates via i2c at address 0x0a and multiplexes access to up + * to four smart batteries at address 0x0b. + * + * Via sysfs interface the online state and charge type are presented. + * + * Datasheet SBSM: http://sbs-forum.org/specs/sbsm100b.pdf + * Datasheet LTC1760: http://cds.linear.com/docs/en/datasheet/1760fb.pdf + * + * Karl-Heinz Schneider + * + * 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 +#include +#include +#include +#include +#include + +#define SBSM_MAX_BATS 4 +#define SBSM_RETRY_CNT 3 + +/* registers addresses */ +#define SBSM_CMD_BATSYSSTATE 0x01 +#define SBSM_CMD_BATSYSSTATECONT 0x02 +#define SBSM_CMD_BATSYSINFO 0x04 +#define SBSM_CMD_LTC 0x3c + +#define SBSM_MASK_BAT_SUPPORTED GENMASK(3, 0) +#define SBSM_MASK_CHARGE_BAT GENMASK(7, 4) +#define SBSM_BIT_AC_PRESENT BIT(0) +#define SBSM_BIT_TURBO BIT(7) + +#define SBSM_SMB_BAT_OFFSET 11 +struct sbsm_data { + struct i2c_client *client; + struct i2c_mux_core *muxc; + + struct power_supply *psy; + + u8 cur_chan; /* currently selected channel */ + struct gpio_chip chip; + bool is_ltc1760; /* special capabilities */ + + unsigned int supported_bats; + unsigned int last_state; + unsigned int last_state_cont; +}; + +static enum power_supply_property sbsm_props[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_CHARGE_TYPE, +}; + +static int sbsm_read_word(struct i2c_client *client, u8 address) +{ + int reg, retries; + + for (retries = SBSM_RETRY_CNT; retries > 0; retries--) { + reg = i2c_smbus_read_word_data(client, address); + if (reg >= 0) + break; + } + + if (reg < 0) { + dev_err(&client->dev, "failed to read register 0x%02x\n", + address); + } + + return reg; +} + +static int sbsm_write_word(struct i2c_client *client, u8 address, u16 word) +{ + int ret, retries; + + for (retries = SBSM_RETRY_CNT; retries > 0; retries--) { + ret = i2c_smbus_write_word_data(client, address, word); + if (ret >= 0) + break; + } + if (ret < 0) + dev_err(&client->dev, "failed to write to register 0x%02x\n", + address); + + return ret; +} + +static int sbsm_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sbsm_data *data = power_supply_get_drvdata(psy); + int regval = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + regval = sbsm_read_word(data->client, SBSM_CMD_BATSYSSTATECONT); + if (regval < 0) + return regval; + val->intval = !!(regval & SBSM_BIT_AC_PRESENT); + break; + + case POWER_SUPPLY_PROP_CHARGE_TYPE: + regval = sbsm_read_word(data->client, SBSM_CMD_BATSYSSTATE); + if (regval < 0) + return regval; + + if ((regval & SBSM_MASK_CHARGE_BAT) == 0) { + val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; + return 0; + } + val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + + if (data->is_ltc1760) { + /* charge mode fast if turbo is active */ + regval = sbsm_read_word(data->client, SBSM_CMD_LTC); + if (regval < 0) + return regval; + else if (regval & SBSM_BIT_TURBO) + val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int sbsm_prop_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + struct sbsm_data *data = power_supply_get_drvdata(psy); + + return (psp == POWER_SUPPLY_PROP_CHARGE_TYPE) && data->is_ltc1760; +} + +static int sbsm_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct sbsm_data *data = power_supply_get_drvdata(psy); + int ret = -EINVAL; + u16 regval; + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_TYPE: + /* write 1 to TURBO if type fast is given */ + if (!data->is_ltc1760) + break; + regval = val->intval == + POWER_SUPPLY_CHARGE_TYPE_FAST ? SBSM_BIT_TURBO : 0; + ret = sbsm_write_word(data->client, SBSM_CMD_LTC, regval); + break; + + default: + break; + } + + return ret; +} + +/* + * Switch to battery + * Parameter chan is directly the content of SMB_BAT* nibble + */ +static int sbsm_select(struct i2c_mux_core *muxc, u32 chan) +{ + struct sbsm_data *data = i2c_mux_priv(muxc); + struct device *dev = &data->client->dev; + int ret = 0; + u16 reg; + + if (data->cur_chan == chan) + return ret; + + /* chan goes from 1 ... 4 */ + reg = 1 << BIT(SBSM_SMB_BAT_OFFSET + chan); + ret = sbsm_write_word(data->client, SBSM_CMD_BATSYSSTATE, reg); + if (ret) + dev_err(dev, "Failed to select channel %i\n", chan); + else + data->cur_chan = chan; + + return ret; +} + +static int sbsm_gpio_get_value(struct gpio_chip *gc, unsigned int off) +{ + struct sbsm_data *data = gpiochip_get_data(gc); + int ret; + + ret = sbsm_read_word(data->client, SBSM_CMD_BATSYSSTATE); + if (ret < 0) + return ret; + + return ret & BIT(off); +} + +/* + * This needs to be defined or the GPIO lib fails to register the pin. + * But the 'gpio' is always an input. + */ +static int sbsm_gpio_direction_input(struct gpio_chip *gc, unsigned int off) +{ + return 0; +} + +static int sbsm_do_alert(struct device *dev, void *d) +{ + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_driver *driver; + + if (!client || client->addr != 0x0b) + return 0; + + device_lock(dev); + if (client->dev.driver) { + driver = to_i2c_driver(client->dev.driver); + if (driver->alert) + driver->alert(client, I2C_PROTOCOL_SMBUS_ALERT, 0); + else + dev_warn(&client->dev, "no driver alert()!\n"); + } else { + dev_dbg(&client->dev, "alert with no driver\n"); + } + device_unlock(dev); + + return -EBUSY; +} + +static void sbsm_alert(struct i2c_client *client, enum i2c_alert_protocol prot, + unsigned int d) +{ + struct sbsm_data *sbsm = i2c_get_clientdata(client); + + int ret, i, irq_bat = 0, state = 0; + + ret = sbsm_read_word(sbsm->client, SBSM_CMD_BATSYSSTATE); + if (ret >= 0) { + irq_bat = ret ^ sbsm->last_state; + sbsm->last_state = ret; + state = ret; + } + + ret = sbsm_read_word(sbsm->client, SBSM_CMD_BATSYSSTATECONT); + if ((ret >= 0) && + ((ret ^ sbsm->last_state_cont) & SBSM_BIT_AC_PRESENT)) { + irq_bat |= sbsm->supported_bats & state; + power_supply_changed(sbsm->psy); + } + sbsm->last_state_cont = ret; + + for (i = 0; i < SBSM_MAX_BATS; i++) { + if (irq_bat & BIT(i)) { + device_for_each_child(&sbsm->muxc->adapter[i]->dev, + NULL, sbsm_do_alert); + } + } +} + +static int sbsm_gpio_setup(struct sbsm_data *data) +{ + struct gpio_chip *gc = &data->chip; + struct i2c_client *client = data->client; + struct device *dev = &client->dev; + int ret; + + if (!device_property_present(dev, "gpio-controller")) + return 0; + + ret = sbsm_read_word(client, SBSM_CMD_BATSYSSTATE); + if (ret < 0) + return ret; + data->last_state = ret; + + ret = sbsm_read_word(client, SBSM_CMD_BATSYSSTATECONT); + if (ret < 0) + return ret; + data->last_state_cont = ret; + + gc->get = sbsm_gpio_get_value; + gc->direction_input = sbsm_gpio_direction_input; + gc->can_sleep = true; + gc->base = -1; + gc->ngpio = SBSM_MAX_BATS; + gc->label = client->name; + gc->parent = dev; + gc->owner = THIS_MODULE; + + ret = devm_gpiochip_add_data(dev, gc, data); + if (ret) { + dev_err(dev, "devm_gpiochip_add_data failed: %d\n", ret); + return ret; + } + + return ret; +} + +static const struct power_supply_desc sbsm_default_psy_desc = { + .type = POWER_SUPPLY_TYPE_MAINS, + .properties = sbsm_props, + .num_properties = ARRAY_SIZE(sbsm_props), + .get_property = &sbsm_get_property, + .set_property = &sbsm_set_property, + .property_is_writeable = &sbsm_prop_is_writeable, +}; + +static int sbsm_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct sbsm_data *data; + struct device *dev = &client->dev; + struct power_supply_desc *psy_desc; + struct power_supply_config psy_cfg = {}; + int ret = 0, i; + + /* Device listens only at address 0x0a */ + if (client->addr != 0x0a) + return -EINVAL; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -EPFNOSUPPORT; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + + data->client = client; + data->is_ltc1760 = !!strstr(id->name, "ltc1760"); + + ret = sbsm_read_word(client, SBSM_CMD_BATSYSINFO); + if (ret < 0) + return ret; + data->supported_bats = ret & SBSM_MASK_BAT_SUPPORTED; + data->muxc = i2c_mux_alloc(adapter, dev, SBSM_MAX_BATS, 0, + I2C_MUX_LOCKED, &sbsm_select, NULL); + if (!data->muxc) { + dev_err(dev, "failed to alloc i2c mux\n"); + ret = -ENOMEM; + goto err_mux_alloc; + } + data->muxc->priv = data; + + /* register muxed i2c channels. One for each supported battery */ + for (i = 0; i < SBSM_MAX_BATS; ++i) { + if (data->supported_bats & BIT(i)) { + ret = i2c_mux_add_adapter(data->muxc, 0, i + 1, 0); + if (ret) + break; + } + } + if (ret) { + dev_err(dev, "failed to register i2c mux channel %d\n", i + 1); + goto err_mux_register; + } + + psy_desc = devm_kmemdup(dev, &sbsm_default_psy_desc, + sizeof(struct power_supply_desc), + GFP_KERNEL); + if (!psy_desc) { + ret = -ENOMEM; + goto err_psy; + } + + psy_desc->name = devm_kasprintf(dev, GFP_KERNEL, "sbsm-%s", + dev_name(&client->dev)); + if (!psy_desc->name) { + ret = -ENOMEM; + goto err_psy; + } + ret = sbsm_gpio_setup(data); + if (ret < 0) + goto err_psy; + + psy_cfg.drv_data = data; + psy_cfg.of_node = dev->of_node; + data->psy = devm_power_supply_register(dev, psy_desc, &psy_cfg); + if (IS_ERR(data->psy)) { + ret = PTR_ERR(data->psy); + dev_err(dev, "failed to register power supply %s\n", + psy_desc->name); + goto err_psy; + } + + return 0; + +err_psy: +err_mux_register: + i2c_mux_del_adapters(data->muxc); + +err_mux_alloc: + return ret; +} + +static int sbsm_remove(struct i2c_client *client) +{ + struct sbsm_data *data = i2c_get_clientdata(client); + + i2c_mux_del_adapters(data->muxc); + return 0; +} + +static const struct i2c_device_id sbsm_ids[] = { + { "sbs-manager", 0 }, + { "ltc1760", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sbsm_ids); + +#ifdef CONFIG_OF +static const struct of_device_id sbsm_dt_ids[] = { + { .compatible = "sbs,sbs-manager" }, + { .compatible = "lltc,ltc1760" }, + { } +}; +MODULE_DEVICE_TABLE(of, sbsm_dt_ids); +#endif + +static struct i2c_driver sbsm_driver = { + .driver = { + .name = "sbsm", + .of_match_table = of_match_ptr(sbsm_dt_ids), + }, + .probe = sbsm_probe, + .remove = sbsm_remove, + .alert = sbsm_alert, + .id_table = sbsm_ids +}; +module_i2c_driver(sbsm_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Karl-Heinz Schneider "); +MODULE_DESCRIPTION("SBSM Smart Battery System Manager"); diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 6d236656aaef..7447d85dbe2f 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -29,6 +29,7 @@ struct gpio_descs { #define GPIOD_FLAGS_BIT_DIR_SET BIT(0) #define GPIOD_FLAGS_BIT_DIR_OUT BIT(1) #define GPIOD_FLAGS_BIT_DIR_VAL BIT(2) +#define GPIOD_FLAGS_BIT_OPEN_DRAIN BIT(3) /** * Optional flags that can be passed to one of gpiod_* to configure direction @@ -40,6 +41,11 @@ enum gpiod_flags { GPIOD_OUT_LOW = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT, GPIOD_OUT_HIGH = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT | GPIOD_FLAGS_BIT_DIR_VAL, + GPIOD_OUT_LOW_OPEN_DRAIN = GPIOD_FLAGS_BIT_DIR_SET | + GPIOD_FLAGS_BIT_DIR_OUT | GPIOD_FLAGS_BIT_OPEN_DRAIN, + GPIOD_OUT_HIGH_OPEN_DRAIN = GPIOD_FLAGS_BIT_DIR_SET | + GPIOD_FLAGS_BIT_DIR_OUT | GPIOD_FLAGS_BIT_DIR_VAL | + GPIOD_FLAGS_BIT_OPEN_DRAIN, }; #ifdef CONFIG_GPIOLIB diff --git a/include/linux/i2c-gpio.h b/include/linux/i2c-gpio.h index c1bcb1f1d73b..352c1426fd4d 100644 --- a/include/linux/i2c-gpio.h +++ b/include/linux/i2c-gpio.h @@ -12,8 +12,6 @@ /** * struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio - * @sda_pin: GPIO pin ID to use for SDA - * @scl_pin: GPIO pin ID to use for SCL * @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz * @timeout: clock stretching timeout in jiffies. If the slave keeps * SCL low for longer than this, the transfer will time out. @@ -26,8 +24,6 @@ * @scl_is_output_only: SCL output drivers cannot be turned off. */ struct i2c_gpio_platform_data { - unsigned int sda_pin; - unsigned int scl_pin; int udelay; int timeout; unsigned int sda_is_open_drain:1; diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h index a1385023a29b..fb0e040b1abb 100644 --- a/include/linux/i2c-smbus.h +++ b/include/linux/i2c-smbus.h @@ -42,7 +42,6 @@ * properly set. */ struct i2c_smbus_alert_setup { - unsigned int alert_edge_triggered:1; int irq; }; @@ -50,4 +49,13 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, struct i2c_smbus_alert_setup *setup); int i2c_handle_smbus_alert(struct i2c_client *ara); +#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF) +int of_i2c_setup_smbus_alert(struct i2c_adapter *adap); +#else +static inline int of_i2c_setup_smbus_alert(struct i2c_adapter *adap) +{ + return 0; +} +#endif + #endif /* _LINUX_I2C_SMBUS_H */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index d501d3956f13..0f774406fad0 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -304,6 +304,7 @@ static inline bool i2c_detect_slave_mode(struct device *dev) { return false; } * @type: chip type, to initialize i2c_client.name * @flags: to initialize i2c_client.flags * @addr: stored in i2c_client.addr + * @dev_name: Overrides the default - dev_name if set * @platform_data: stored in i2c_client.dev.platform_data * @archdata: copied into i2c_client.dev.archdata * @of_node: pointer to OpenFirmware device node @@ -328,6 +329,7 @@ struct i2c_board_info { char type[I2C_NAME_SIZE]; unsigned short flags; unsigned short addr; + const char *dev_name; void *platform_data; struct dev_archdata *archdata; struct device_node *of_node; diff --git a/include/linux/platform_data/i2c-nuc900.h b/include/linux/platform_data/i2c-nuc900.h deleted file mode 100644 index 23036273a97e..000000000000 --- a/include/linux/platform_data/i2c-nuc900.h +++ /dev/null @@ -1,10 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_ARCH_NUC900_I2C_H -#define __ASM_ARCH_NUC900_I2C_H - -struct nuc900_platform_i2c { - int bus_num; - unsigned long bus_freq; -}; - -#endif /* __ASM_ARCH_NUC900_I2C_H */