forked from luck/tmp_suning_uos_patched
Merge branch 'i2c/for-4.15' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "This contains two bigger than usual tree-wide changes this time. They all have proper acks, caused no merge conflicts in linux-next where they have been for a while. They are namely: - to-gpiod conversion of the i2c-gpio driver and its users (touching arch/* and drivers/mfd/*) - adding a sbs-manager based on I2C core updates to SMBus alerts (touching drivers/power/*) Other notable changes: - i2c_boardinfo can now carry a dev_name to be used when the device is created. This is because some devices in ACPI world need fixed names to find the regulators. - the designware driver got a long discussed overhaul of its PM handling. img-scb and davinci got PM support, too. - at24 driver has way better OF support. And it has a new maintainer. Thanks Bartosz for stepping up! The rest is regular driver updates and fixes" * 'i2c/for-4.15' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (55 commits) ARM: sa1100: simpad: Correct I2C GPIO offsets i2c: aspeed: Deassert reset in probe eeprom: at24: Add OF device ID table MAINTAINERS: new maintainer for AT24 driver i2c: nuc900: remove platform_data, too i2c: thunderx: Remove duplicate NULL check i2c: taos-evm: Remove duplicate NULL check i2c: Make i2c_unregister_device() NULL-aware i2c: xgene-slimpro: Support v2 i2c: mpc: remove useless variable initialization i2c: omap: Trigger bus recovery in lockup case i2c: gpio: Add support for named gpios in DT dt-bindings: i2c: i2c-gpio: Add support for named gpios i2c: gpio: Local vars in probe i2c: gpio: Augment all boardfiles to use open drain i2c: gpio: Enforce open drain through gpiolib gpio: Make it possible for consumers to enforce open drain i2c: gpio: Convert to use descriptors power: supply: sbs-message: fix some code style issues power: supply: sbs-battery: remove unchecked return var ...
This commit is contained in:
commit
4008e6a9bc
|
@ -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 {
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 <dt-bindings/gpio/gpio.h> 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 <dt-bindings/gpio/gpio.h> 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 <dt-bindings/gpio/gpio.h>
|
||||
|
||||
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>;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
Binding for sbs-manager
|
||||
|
||||
Required properties:
|
||||
- compatible: "<vendor>,<part-number>", "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>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -2249,7 +2249,7 @@ F: include/linux/dmaengine.h
|
|||
F: include/linux/async_tx.h
|
||||
|
||||
AT24 EEPROM DRIVER
|
||||
M: Wolfram Sang <wsa@the-dreams.de>
|
||||
M: Bartosz Golaszewski <brgl@bgdev.pl>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/misc/eeprom/at24.c
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <linux/amba/serial.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/irqchip/arm-vic.h>
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <sound/cs4271.h>
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <linux/reboot.h>
|
||||
|
||||
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);
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/mmc_spi.h>
|
||||
|
@ -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));
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
@ -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();
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/platform_data/pca953x.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
|
@ -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));
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <linux/serial.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <asm/types.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/memory.h>
|
||||
|
@ -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);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <linux/leds.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <linux/leds.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
@ -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));
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/hdlc.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -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");
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <linux/serial.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <linux/leds.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
@ -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));
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <linux/leds.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
@ -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));
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
|
@ -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,
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/power_supply.h>
|
||||
#include <linux/usb/gpio_vbus.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/suspend.h>
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/i2c/pxa-i2c.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/smc91x.h>
|
||||
|
@ -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));
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/setup.h>
|
||||
|
@ -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");
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
#include <asm/portmux.h>
|
||||
|
@ -362,11 +363,17 @@ static struct platform_device bfin_device_gpiokeys = {
|
|||
#if IS_ENABLED(CONFIG_I2C_GPIO)
|
||||
#include <linux/i2c-gpio.h>
|
||||
|
||||
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));
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#endif
|
||||
#include <linux/irq.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
#include <asm/portmux.h>
|
||||
|
@ -390,11 +391,17 @@ static struct platform_device bfin_device_gpiokeys = {
|
|||
#if IS_ENABLED(CONFIG_I2C_GPIO)
|
||||
#include <linux/i2c-gpio.h>
|
||||
|
||||
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,
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
#include <asm/reboot.h>
|
||||
|
@ -512,11 +513,17 @@ static struct platform_device bfin_device_gpiokeys = {
|
|||
#if IS_ENABLED(CONFIG_I2C_GPIO)
|
||||
#include <linux/i2c-gpio.h>
|
||||
|
||||
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));
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
#include <asm/portmux.h>
|
||||
|
@ -379,11 +380,17 @@ static struct platform_device bfin_device_gpiokeys = {
|
|||
#if IS_ENABLED(CONFIG_I2C_GPIO)
|
||||
#include <linux/i2c-gpio.h>
|
||||
|
||||
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;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/idle.h>
|
||||
#include <asm/reboot.h>
|
||||
|
@ -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));
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/platform_data/pcf857x.h>
|
||||
|
||||
#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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* 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;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include <linux/mfd/intel_soc_pmic.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power/bq24190_charger.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#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);
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_data/i2c-davinci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
/* ----- 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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -14,27 +14,17 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
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" : "");
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
|
@ -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 @@ static unsigned int img_i2c_atomic(struct img_i2c *i2c,
|
|||
* 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" },
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -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;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-smbus.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/irqflags.h>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-smbus.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/smbus.h>
|
||||
|
@ -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
|
||||
|
|
|
@ -21,12 +21,11 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/sm501.h>
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
|
@ -24,6 +25,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
#include <linux/platform_data/at24.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
/*
|
||||
* 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 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
445
drivers/power/supply/sbs-manager.c
Normal file
445
drivers/power/supply/sbs-manager.c
Normal file
|
@ -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 <karl-heinz@schneider-inet.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#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 <karl-heinz@schneider-inet.de>");
|
||||
MODULE_DESCRIPTION("SBSM Smart Battery System Manager");
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 <busnr>-<addr> 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;
|
||||
|
|
|
@ -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 */
|
Loading…
Reference in New Issue
Block a user