mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge branch 'i2c/i2c-next' of https://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/altr,softip-i2c-v1.0.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Altera I2C Controller
|
||||
|
||||
maintainers:
|
||||
- Thor Thayer <thor.thayer@linux.intel.com>
|
||||
- Chaitanya Sabnis <chaitanya.msabnis@gmail.com>
|
||||
|
||||
description:
|
||||
Altera's synthesizable logic block I2C Controller for use in Altera's FPGAs.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: altr,softip-i2c-v1.0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
fifo-size:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Size of the RX and TX FIFOs in bytes.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c@80000 {
|
||||
compatible = "altr,softip-i2c-v1.0";
|
||||
reg = <0x80000 0x40>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 43 4>;
|
||||
clocks = <&clk_0>;
|
||||
clock-frequency = <100000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
fifo-size = <4>;
|
||||
|
||||
eeprom@51 {
|
||||
compatible = "atmel,24c32";
|
||||
reg = <0x51>;
|
||||
pagesize = <32>;
|
||||
};
|
||||
};
|
||||
@@ -14,9 +14,13 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- cdns,i2c-r1p10 # cadence i2c controller version 1.0
|
||||
- cdns,i2c-r1p14 # cadence i2c controller version 1.4
|
||||
oneOf:
|
||||
- enum:
|
||||
- cdns,i2c-r1p10 # cadence i2c controller version 1.0
|
||||
- cdns,i2c-r1p14 # cadence i2c controller version 1.4
|
||||
- items:
|
||||
- const: axiado,ax3005-i2c
|
||||
- const: cdns,i2c-r1p14
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
* Altera I2C Controller
|
||||
* This is Altera's synthesizable logic block I2C Controller for use
|
||||
* in Altera's FPGAs.
|
||||
|
||||
Required properties :
|
||||
- compatible : should be "altr,softip-i2c-v1.0"
|
||||
- reg : Offset and length of the register set for the device
|
||||
- interrupts : <IRQ> where IRQ is the interrupt number.
|
||||
- clocks : phandle to input clock.
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
|
||||
Recommended properties :
|
||||
- clock-frequency : desired I2C bus clock frequency in Hz.
|
||||
|
||||
Optional properties :
|
||||
- fifo-size : Size of the RX and TX FIFOs in bytes.
|
||||
- Child nodes conforming to i2c bus binding
|
||||
|
||||
Example :
|
||||
|
||||
i2c@100080000 {
|
||||
compatible = "altr,softip-i2c-v1.0";
|
||||
reg = <0x00000001 0x00080000 0x00000040>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 43 4>;
|
||||
clocks = <&clk_0>;
|
||||
clock-frequency = <100000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
fifo-size = <4>;
|
||||
|
||||
eeprom@51 {
|
||||
compatible = "atmel,24c32";
|
||||
reg = <0x51>;
|
||||
pagesize = <32>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
LSI Axxia I2C
|
||||
|
||||
Required properties :
|
||||
- compatible : Must be "lsi,api2c"
|
||||
- reg : Offset and length of the register set for the device
|
||||
- interrupts : the interrupt specifier
|
||||
- #address-cells : Must be <1>;
|
||||
- #size-cells : Must be <0>;
|
||||
- clock-names : Must contain "i2c".
|
||||
- clocks: Must contain an entry for each name in clock-names. See the common
|
||||
clock bindings.
|
||||
|
||||
Optional properties :
|
||||
- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified,
|
||||
the default 100 kHz frequency will be used. As only Normal and Fast modes
|
||||
are supported, possible values are 100000 and 400000.
|
||||
|
||||
Example :
|
||||
|
||||
i2c@2010084000 {
|
||||
compatible = "lsi,api2c";
|
||||
device_type = "i2c";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x20 0x10084000 0x00 0x1000>;
|
||||
interrupts = <0 19 4>;
|
||||
clocks = <&clk_per>;
|
||||
clock-names = "i2c";
|
||||
clock-frequency = <400000>;
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/lsi,api2c.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: LSI Axxia I2C Controller
|
||||
|
||||
maintainers:
|
||||
- Anders Berg <anders.berg@lsi.com>
|
||||
- Chaitanya Sabnis <chaitanya.msabnis@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: lsi,api2c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: i2c
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c@10084000 {
|
||||
compatible = "lsi,api2c";
|
||||
reg = <0x10084000 0x1000>;
|
||||
interrupts = <0 19 4>;
|
||||
clocks = <&clk_per>;
|
||||
clock-names = "i2c";
|
||||
clock-frequency = <400000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/qcom,sa8255p-geni-i2c.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm SA8255p QUP GENI I2C Controller
|
||||
|
||||
maintainers:
|
||||
- Praveen Talari <praveen.talari@oss.qualcomm.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: qcom,sa8255p-geni-i2c
|
||||
- items:
|
||||
- const: qcom,sa8797p-geni-i2c
|
||||
- const: qcom,sa8255p-geni-i2c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
maxItems: 2
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 2
|
||||
|
||||
power-domain-names:
|
||||
items:
|
||||
- const: power
|
||||
- const: perf
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- power-domains
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/dma/qcom-gpi.h>
|
||||
|
||||
i2c@a90000 {
|
||||
compatible = "qcom,sa8255p-geni-i2c";
|
||||
reg = <0xa90000 0x4000>;
|
||||
interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>,
|
||||
<&gpi_dma0 1 0 QCOM_GPI_I2C>;
|
||||
dma-names = "tx", "rx";
|
||||
power-domains = <&scmi0_pd 0>, <&scmi0_dvfs 0>;
|
||||
power-domain-names = "power", "perf";
|
||||
};
|
||||
...
|
||||
@@ -56,6 +56,11 @@ properties:
|
||||
- renesas,i2c-r8a779h0 # R-Car V4M
|
||||
- const: renesas,rcar-gen4-i2c # R-Car Gen4
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,i2c-r8a78000 # R-Car X5H
|
||||
- const: renesas,rcar-gen5-i2c # R-Car Gen5
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -140,6 +145,7 @@ allOf:
|
||||
- renesas,rcar-gen2-i2c
|
||||
- renesas,rcar-gen3-i2c
|
||||
- renesas,rcar-gen4-i2c
|
||||
- renesas,rcar-gen5-i2c
|
||||
then:
|
||||
required:
|
||||
- resets
|
||||
|
||||
@@ -639,7 +639,7 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
|
||||
struct i2c_algo_bit_data *bit_adap = adap->algo_data;
|
||||
int ret;
|
||||
|
||||
if (bit_test) {
|
||||
if (bit_test && !bit_adap->skip_bit_test) {
|
||||
ret = test_bus(adap);
|
||||
if (bit_test >= 2 && ret < 0)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -793,7 +793,7 @@ config I2C_JZ4780
|
||||
config I2C_K1
|
||||
tristate "SpacemiT K1 I2C adapter"
|
||||
depends on ARCH_SPACEMIT || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on OF && COMMON_CLK
|
||||
default ARCH_SPACEMIT
|
||||
help
|
||||
This option enables support for the I2C interface on the SpacemiT K1
|
||||
|
||||
@@ -89,6 +89,10 @@ static void amd_asf_process_target(struct work_struct *work)
|
||||
outb_p(reg, ASFDATABNKSEL);
|
||||
cmd = inb_p(ASFINDEX);
|
||||
len = inb_p(ASFDATARWPTR);
|
||||
|
||||
if (len > ASF_BLOCK_MAX_BYTES)
|
||||
return;
|
||||
|
||||
for (idx = 0; idx < len; idx++)
|
||||
data[idx] = inb_p(ASFINDEX);
|
||||
|
||||
@@ -333,11 +337,11 @@ static int amd_asf_probe(struct platform_device *pdev)
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return dev_err_probe(dev, irq, "missing IRQ resources\n");
|
||||
return irq;
|
||||
|
||||
ret = devm_request_irq(dev, irq, amd_asf_irq_handler, IRQF_SHARED, "amd_asf", asf_dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Unable to request irq: %d for use\n", irq);
|
||||
return ret;
|
||||
|
||||
asf_dev->adap.owner = THIS_MODULE;
|
||||
asf_dev->adap.algo = &amd_asf_smbus_algorithm;
|
||||
|
||||
@@ -1147,8 +1147,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev)
|
||||
bcm_iproc_i2c_isr, 0, pdev->name,
|
||||
iproc_i2c);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(iproc_i2c->device, ret,
|
||||
"unable to request irq %i\n", irq);
|
||||
return ret;
|
||||
|
||||
iproc_i2c->irq = irq;
|
||||
} else {
|
||||
|
||||
@@ -117,8 +117,6 @@
|
||||
/* timeout for pm runtime autosuspend */
|
||||
#define DAVINCI_I2C_PM_TIMEOUT 1000 /* ms */
|
||||
|
||||
#define DAVINCI_I2C_DEFAULT_BUS_FREQ 100000
|
||||
|
||||
struct davinci_i2c_dev {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
@@ -760,7 +758,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop);
|
||||
if (r)
|
||||
prop = DAVINCI_I2C_DEFAULT_BUS_FREQ;
|
||||
prop = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
|
||||
dev->bus_freq = prop / 1000;
|
||||
|
||||
|
||||
+209
-14
@@ -18,9 +18,21 @@
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static LIST_HEAD(i2c_gpio_scl_list);
|
||||
static DEFINE_MUTEX(i2c_gpio_scl_list_lock);
|
||||
static struct lock_class_key i2c_gpio_scl_lock_key;
|
||||
|
||||
struct i2c_gpio_scl_data {
|
||||
struct fwnode_reference_args args;
|
||||
struct gpio_desc *gpio;
|
||||
struct rt_mutex lock;
|
||||
struct list_head list;
|
||||
refcount_t ref;
|
||||
};
|
||||
|
||||
struct i2c_gpio_private_data {
|
||||
struct gpio_desc *sda;
|
||||
struct gpio_desc *scl;
|
||||
struct i2c_gpio_scl_data *scl;
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_algo_bit_data bit_data;
|
||||
struct i2c_gpio_platform_data pdata;
|
||||
@@ -31,6 +43,11 @@ struct i2c_gpio_private_data {
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline struct i2c_gpio_private_data *adap_to_priv(struct i2c_adapter *adap)
|
||||
{
|
||||
return container_of(adap, struct i2c_gpio_private_data, adap);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -53,7 +70,7 @@ static void i2c_gpio_setscl_val(void *data, int state)
|
||||
{
|
||||
struct i2c_gpio_private_data *priv = data;
|
||||
|
||||
gpiod_set_value_cansleep(priv->scl, state);
|
||||
gpiod_set_value_cansleep(priv->scl->gpio, state);
|
||||
}
|
||||
|
||||
static int i2c_gpio_getsda(void *data)
|
||||
@@ -67,9 +84,41 @@ static int i2c_gpio_getscl(void *data)
|
||||
{
|
||||
struct i2c_gpio_private_data *priv = data;
|
||||
|
||||
return gpiod_get_value_cansleep(priv->scl);
|
||||
return gpiod_get_value_cansleep(priv->scl->gpio);
|
||||
}
|
||||
|
||||
static void i2c_gpio_lock_bus(struct i2c_adapter *adap, unsigned int flags)
|
||||
{
|
||||
/* Take care about adapter lock. See i2c_adapter_lock_bus() and others. */
|
||||
rt_mutex_lock_nested(&adap->bus_lock, i2c_adapter_depth(adap));
|
||||
rt_mutex_lock(&adap_to_priv(adap)->scl->lock);
|
||||
}
|
||||
|
||||
static int i2c_gpio_trylock_bus(struct i2c_adapter *adap, unsigned int flags)
|
||||
{
|
||||
if (!rt_mutex_trylock(&adap->bus_lock))
|
||||
return 0;
|
||||
|
||||
if (!rt_mutex_trylock(&adap_to_priv(adap)->scl->lock)) {
|
||||
rt_mutex_unlock(&adap->bus_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void i2c_gpio_unlock_bus(struct i2c_adapter *adap, unsigned int flags)
|
||||
{
|
||||
rt_mutex_unlock(&adap_to_priv(adap)->scl->lock);
|
||||
rt_mutex_unlock(&adap->bus_lock);
|
||||
}
|
||||
|
||||
static const struct i2c_lock_operations i2c_gpio_lock_ops = {
|
||||
.lock_bus = i2c_gpio_lock_bus,
|
||||
.trylock_bus = i2c_gpio_trylock_bus,
|
||||
.unlock_bus = i2c_gpio_unlock_bus,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR
|
||||
|
||||
#define setsda(bd, val) ((bd)->setsda((bd)->data, val))
|
||||
@@ -165,14 +214,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write
|
||||
static int i2c_gpio_fi_act_on_scl_irq(struct i2c_gpio_private_data *priv,
|
||||
irqreturn_t handler(int, void*))
|
||||
{
|
||||
int ret, irq = gpiod_to_irq(priv->scl);
|
||||
int ret, irq = gpiod_to_irq(priv->scl->gpio);
|
||||
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
|
||||
|
||||
ret = gpiod_direction_input(priv->scl);
|
||||
ret = gpiod_direction_input(priv->scl->gpio);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
@@ -187,7 +236,7 @@ static int i2c_gpio_fi_act_on_scl_irq(struct i2c_gpio_private_data *priv,
|
||||
|
||||
free_irq(irq, priv);
|
||||
output:
|
||||
ret = gpiod_direction_output(priv->scl, 1) ?: ret;
|
||||
ret = gpiod_direction_output(priv->scl->gpio, 1) ?: ret;
|
||||
unlock:
|
||||
i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
|
||||
|
||||
@@ -308,13 +357,17 @@ static struct gpio_desc *i2c_gpio_get_desc(struct device *dev,
|
||||
struct gpio_desc *retdesc;
|
||||
int ret;
|
||||
|
||||
retdesc = devm_gpiod_get(dev, con_id, gflags);
|
||||
/*
|
||||
* Don't use resource-managed functions. SCL may be shared across adapters and has
|
||||
* its own lifetime management. SDA uses the same path for consistency.
|
||||
*/
|
||||
retdesc = 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);
|
||||
retdesc = gpiod_get_index(dev, NULL, index, gflags);
|
||||
if (!IS_ERR(retdesc)) {
|
||||
dev_dbg(dev, "got GPIO from index %u\n", index);
|
||||
return retdesc;
|
||||
@@ -336,6 +389,134 @@ static struct gpio_desc *i2c_gpio_get_desc(struct device *dev,
|
||||
return retdesc;
|
||||
}
|
||||
|
||||
static struct i2c_gpio_scl_data *i2c_gpio_create_scl(struct device *dev)
|
||||
{
|
||||
struct fwnode_handle *fwnode = dev_fwnode(dev);
|
||||
struct fwnode_reference_args args;
|
||||
struct i2c_gpio_scl_data *scl;
|
||||
bool sharable = false;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* SCL gpios can be shared if they are defined in the devicetree and have at least one
|
||||
* cell in addition to the phandle. This is usually the pin. To support complex designs
|
||||
* with arbitrary of_xlate() mappings handle the node cells opaque.
|
||||
*/
|
||||
if (fwnode) {
|
||||
ret = fwnode_property_get_reference_args(fwnode, "scl-gpios",
|
||||
"#gpio-cells", 0, 0, &args);
|
||||
if (ret)
|
||||
/* try the ancient way */
|
||||
ret = fwnode_property_get_reference_args(fwnode, "gpios",
|
||||
"#gpio-cells", 0, 1, &args);
|
||||
|
||||
if (!ret) {
|
||||
if (args.nargs >= 1)
|
||||
sharable = true;
|
||||
else
|
||||
fwnode_handle_put(args.fwnode);
|
||||
}
|
||||
}
|
||||
|
||||
scl = kzalloc(sizeof(*scl), GFP_KERNEL);
|
||||
if (!scl) {
|
||||
if (sharable)
|
||||
fwnode_handle_put(args.fwnode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
if (sharable) {
|
||||
scl->args.fwnode = args.fwnode;
|
||||
scl->args.nargs = args.nargs;
|
||||
memcpy(scl->args.args, args.args, sizeof(args.args[0]) * args.nargs);
|
||||
}
|
||||
|
||||
rt_mutex_init(&scl->lock);
|
||||
lockdep_set_class(&scl->lock, &i2c_gpio_scl_lock_key);
|
||||
refcount_set(&scl->ref, 1);
|
||||
|
||||
return scl;
|
||||
}
|
||||
|
||||
static void i2c_gpio_free_scl(struct i2c_gpio_scl_data *scl)
|
||||
{
|
||||
if (scl->args.fwnode)
|
||||
fwnode_handle_put(scl->args.fwnode);
|
||||
kfree(scl);
|
||||
}
|
||||
|
||||
static bool i2c_gpio_scl_matches(struct i2c_gpio_scl_data *a, struct i2c_gpio_scl_data *b)
|
||||
{
|
||||
if (!a->args.fwnode || !b->args.fwnode ||
|
||||
a->args.fwnode != b->args.fwnode || a->args.nargs != b->args.nargs)
|
||||
return false;
|
||||
|
||||
return memcmp(a->args.args, b->args.args, sizeof(a->args.args[0]) * a->args.nargs) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up an existing or create a new shared SCL structure. Optimistic setup sequence always
|
||||
* creates and tries to add a new entry to the list. This uses minimum locking and afterwards
|
||||
* requests the GPIO without a lock held. Concurrent probes for the same SCL pin see the entry
|
||||
* and do not race into a second gpiod_get(). Until everything is setup they terminate with
|
||||
* -EPROBE_DEFER.
|
||||
*/
|
||||
static struct i2c_gpio_scl_data *i2c_gpio_lookup_scl(struct device *dev, enum gpiod_flags gflags)
|
||||
{
|
||||
struct i2c_gpio_scl_data *scl, *new_scl;
|
||||
struct gpio_desc *gpio;
|
||||
|
||||
new_scl = i2c_gpio_create_scl(dev);
|
||||
if (IS_ERR(new_scl))
|
||||
return new_scl;
|
||||
|
||||
scoped_guard(mutex, &i2c_gpio_scl_list_lock) {
|
||||
list_for_each_entry(scl, &i2c_gpio_scl_list, list) {
|
||||
if (!i2c_gpio_scl_matches(scl, new_scl))
|
||||
continue;
|
||||
|
||||
i2c_gpio_free_scl(new_scl);
|
||||
if (!scl->gpio)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
refcount_inc(&scl->ref);
|
||||
if (scl->args.fwnode)
|
||||
dev_dbg(dev, "reusing shared SCL (%pfwP)\n", scl->args.fwnode);
|
||||
|
||||
return scl;
|
||||
}
|
||||
list_add(&new_scl->list, &i2c_gpio_scl_list);
|
||||
}
|
||||
|
||||
gpio = i2c_gpio_get_desc(dev, "scl", 1, gflags);
|
||||
if (IS_ERR(gpio)) {
|
||||
scoped_guard(mutex, &i2c_gpio_scl_list_lock)
|
||||
list_del(&new_scl->list);
|
||||
i2c_gpio_free_scl(new_scl);
|
||||
|
||||
return ERR_CAST(gpio);
|
||||
}
|
||||
|
||||
scoped_guard(mutex, &i2c_gpio_scl_list_lock)
|
||||
new_scl->gpio = gpio;
|
||||
|
||||
if (new_scl->args.fwnode)
|
||||
dev_dbg(dev, "registered shared SCL (%pfwP)\n", new_scl->args.fwnode);
|
||||
|
||||
return new_scl;
|
||||
}
|
||||
|
||||
static void i2c_gpio_cleanup_scl(struct i2c_gpio_scl_data *scl)
|
||||
{
|
||||
if (!refcount_dec_and_mutex_lock(&scl->ref, &i2c_gpio_scl_list_lock))
|
||||
return;
|
||||
|
||||
list_del(&scl->list);
|
||||
mutex_unlock(&i2c_gpio_scl_list_lock);
|
||||
gpiod_put(scl->gpio);
|
||||
i2c_gpio_free_scl(scl);
|
||||
}
|
||||
|
||||
static int i2c_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_gpio_private_data *priv;
|
||||
@@ -386,15 +567,18 @@ static int i2c_gpio_probe(struct platform_device *pdev)
|
||||
gflags = GPIOD_OUT_HIGH;
|
||||
else
|
||||
gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
|
||||
priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags);
|
||||
if (IS_ERR(priv->scl))
|
||||
return PTR_ERR(priv->scl);
|
||||
priv->scl = i2c_gpio_lookup_scl(dev, gflags);
|
||||
if (IS_ERR(priv->scl)) {
|
||||
ret = PTR_ERR(priv->scl);
|
||||
goto err_cleanup_sda;
|
||||
}
|
||||
|
||||
if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl))
|
||||
if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl->gpio))
|
||||
dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing");
|
||||
else
|
||||
bit_data->can_do_atomic = true;
|
||||
|
||||
bit_data->skip_bit_test = !!priv->scl->args.fwnode;
|
||||
bit_data->setsda = i2c_gpio_setsda_val;
|
||||
bit_data->setscl = i2c_gpio_setscl_val;
|
||||
|
||||
@@ -423,6 +607,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
|
||||
else
|
||||
snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
|
||||
|
||||
/* Always use shared SCL aware locking */
|
||||
adap->lock_ops = &i2c_gpio_lock_ops;
|
||||
adap->algo_data = bit_data;
|
||||
adap->class = I2C_CLASS_HWMON;
|
||||
adap->dev.parent = dev;
|
||||
@@ -431,7 +617,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
|
||||
adap->nr = pdev->id;
|
||||
ret = i2c_bit_add_numbered_bus(adap);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_cleanup_scl;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
@@ -441,13 +627,20 @@ static int i2c_gpio_probe(struct platform_device *pdev)
|
||||
* 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),
|
||||
desc_to_gpio(priv->sda), desc_to_gpio(priv->scl->gpio),
|
||||
pdata->scl_is_output_only
|
||||
? ", no clock stretching" : "");
|
||||
|
||||
i2c_gpio_fault_injector_init(pdev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_cleanup_scl:
|
||||
i2c_gpio_cleanup_scl(priv->scl);
|
||||
err_cleanup_sda:
|
||||
gpiod_put(priv->sda);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void i2c_gpio_remove(struct platform_device *pdev)
|
||||
@@ -459,6 +652,8 @@ static void i2c_gpio_remove(struct platform_device *pdev)
|
||||
adap = &priv->adap;
|
||||
|
||||
i2c_del_adapter(adap);
|
||||
i2c_gpio_cleanup_scl(priv->scl);
|
||||
gpiod_put(priv->sda);
|
||||
}
|
||||
|
||||
static const struct of_device_id i2c_gpio_dt_ids[] = {
|
||||
|
||||
@@ -551,7 +551,7 @@ static int gxp_i2c_probe(struct platform_device *pdev)
|
||||
rc = devm_request_irq(&pdev->dev, drvdata->irq, gxp_i2c_irq_handler,
|
||||
IRQF_SHARED, gxp_i2c_name[drvdata->engine], drvdata);
|
||||
if (rc < 0)
|
||||
return dev_err_probe(&pdev->dev, rc, "irq request failed\n");
|
||||
return rc;
|
||||
|
||||
i2c_parse_fw_timings(&pdev->dev, &drvdata->t, true);
|
||||
|
||||
|
||||
@@ -481,7 +481,7 @@ static int hisi_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
ret = devm_request_irq(dev, ctlr->irq, hisi_i2c_irq, 0, "hisi-i2c", ctlr);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to request irq handler\n");
|
||||
return ret;
|
||||
|
||||
ctlr->clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR_OR_NULL(ctlr->clk)) {
|
||||
|
||||
@@ -1510,11 +1510,6 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
lpi2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
|
||||
pdev->name, lpi2c_imx);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "can't claim irq %d\n", lpi2c_imx->irq);
|
||||
|
||||
i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx);
|
||||
platform_set_drvdata(pdev, lpi2c_imx);
|
||||
|
||||
@@ -1527,14 +1522,18 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
|
||||
* each transfer
|
||||
*/
|
||||
ret = devm_clk_rate_exclusive_get(&pdev->dev, lpi2c_imx->clks[0].clk);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"can't lock I2C peripheral clock rate\n");
|
||||
if (ret) {
|
||||
ret = dev_err_probe(&pdev->dev, ret,
|
||||
"can't lock I2C peripheral clock rate\n");
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
lpi2c_imx->rate_per = clk_get_rate(lpi2c_imx->clks[0].clk);
|
||||
if (!lpi2c_imx->rate_per)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"can't get I2C peripheral clock rate\n");
|
||||
if (!lpi2c_imx->rate_per) {
|
||||
ret = dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"can't get I2C peripheral clock rate\n");
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
if (lpi2c_imx->hwdata->need_prepare_unprepare_clk)
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_LONG_TIMEOUT_MS);
|
||||
@@ -1546,6 +1545,20 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
/*
|
||||
* Reset all internal controller registers of both Master and Target
|
||||
* to avoid effects of previous status.
|
||||
*/
|
||||
writel(MCR_RST, lpi2c_imx->base + LPI2C_MCR);
|
||||
writel(SCR_RST, lpi2c_imx->base + LPI2C_SCR);
|
||||
writel(0, lpi2c_imx->base + LPI2C_MCR);
|
||||
writel(0, lpi2c_imx->base + LPI2C_SCR);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
|
||||
pdev->name, lpi2c_imx);
|
||||
if (ret)
|
||||
goto rpm_disable;
|
||||
|
||||
temp = readl(lpi2c_imx->base + LPI2C_PARAM);
|
||||
lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
|
||||
lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
|
||||
@@ -1576,8 +1589,11 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
|
||||
|
||||
rpm_disable:
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
clk_disable:
|
||||
clk_bulk_disable_unprepare(lpi2c_imx->num_clks, lpi2c_imx->clks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1753,7 +1753,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return dev_err_probe(&pdev->dev, irq, "can't get IRQ\n");
|
||||
return irq;
|
||||
|
||||
base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(base))
|
||||
|
||||
+170
-17
@@ -4,7 +4,9 @@
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
@@ -17,6 +19,8 @@
|
||||
#define SPACEMIT_ISR 0x4 /* Status register */
|
||||
#define SPACEMIT_IDBR 0xc /* Data buffer register */
|
||||
#define SPACEMIT_IRCR 0x18 /* Reset cycle counter */
|
||||
#define SPACEMIT_ILCR 0x10 /* Load Count Register */
|
||||
#define SPACEMIT_IWCR 0x14 /* Wait Count Register */
|
||||
#define SPACEMIT_IBMR 0x1c /* Bus monitor register */
|
||||
|
||||
/* SPACEMIT_ICR register fields */
|
||||
@@ -88,12 +92,22 @@
|
||||
#define SPACEMIT_BMR_SDA BIT(0) /* SDA line level */
|
||||
#define SPACEMIT_BMR_SCL BIT(1) /* SCL line level */
|
||||
|
||||
#define SPACEMIT_LCR_LV_STANDARD_MASK GENMASK(8, 0)
|
||||
#define SPACEMIT_LCR_LV_FAST_MASK GENMASK(17, 9)
|
||||
|
||||
/* SPACEMIT_IWCR register fields */
|
||||
#define SPACEMIT_WCR_COUNT GENMASK(4, 0)
|
||||
#define SPACEMIT_WCR_HS_COUNT1 GENMASK(9, 5)
|
||||
#define SPACEMIT_WCR_HS_COUNT2 GENMASK(14, 10)
|
||||
|
||||
/* Required by I2C IP for correct SCL timing */
|
||||
#define SPACEMIT_IWCR_INIT_VALUE (FIELD_PREP(SPACEMIT_WCR_COUNT, 10) | \
|
||||
FIELD_PREP(SPACEMIT_WCR_HS_COUNT1, 1) | \
|
||||
FIELD_PREP(SPACEMIT_WCR_HS_COUNT2, 5))
|
||||
|
||||
/* i2c bus recover timeout: us */
|
||||
#define SPACEMIT_I2C_BUS_BUSY_TIMEOUT 100000
|
||||
|
||||
#define SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ 100000 /* Hz */
|
||||
#define SPACEMIT_I2C_MAX_FAST_MODE_FREQ 400000 /* Hz */
|
||||
|
||||
#define SPACEMIT_SR_ERR (SPACEMIT_SR_BED | SPACEMIT_SR_RXOV | SPACEMIT_SR_ALD)
|
||||
|
||||
#define SPACEMIT_BUS_RESET_CLK_CNT_MAX 9
|
||||
@@ -109,11 +123,20 @@ enum spacemit_i2c_state {
|
||||
SPACEMIT_STATE_WRITE,
|
||||
};
|
||||
|
||||
enum spacemit_i2c_mode {
|
||||
SPACEMIT_MODE_STANDARD,
|
||||
SPACEMIT_MODE_FAST
|
||||
};
|
||||
|
||||
/* i2c-spacemit driver's main struct */
|
||||
struct spacemit_i2c_dev {
|
||||
struct device *dev;
|
||||
struct i2c_adapter adapt;
|
||||
|
||||
struct clk_hw scl_clk_hw;
|
||||
struct clk *scl_clk;
|
||||
enum spacemit_i2c_mode mode;
|
||||
|
||||
/* hardware resources */
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
@@ -135,6 +158,85 @@ struct spacemit_i2c_dev {
|
||||
u32 status;
|
||||
};
|
||||
|
||||
static void spacemit_i2c_scl_clk_disable_unprepare(void *data)
|
||||
{
|
||||
clk_disable_unprepare(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the ILCR divider value (lv) from the target SCL rate.
|
||||
*
|
||||
* Hardware timing formulas:
|
||||
* - standard mode: SCL = FCLK / (2 * SLV + 8)
|
||||
* - fast mode: SCL = FCLK / (2 * FLV + 10)
|
||||
*/
|
||||
static u32 spacemit_i2c_calc_lv(struct spacemit_i2c_dev *i2c,
|
||||
unsigned long parent_rate,
|
||||
unsigned long target_rate)
|
||||
{
|
||||
u32 offset, denom;
|
||||
|
||||
offset = (i2c->mode == SPACEMIT_MODE_STANDARD) ? 8 : 10;
|
||||
denom = DIV_ROUND_CLOSEST(parent_rate, target_rate);
|
||||
|
||||
return (denom <= offset) ? 0 : DIV_ROUND_CLOSEST(denom - offset, 2);
|
||||
}
|
||||
|
||||
static int spacemit_i2c_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
|
||||
u32 lv, lcr, mask;
|
||||
|
||||
lv = spacemit_i2c_calc_lv(i2c, parent_rate, rate);
|
||||
|
||||
mask = (i2c->mode == SPACEMIT_MODE_STANDARD) ?
|
||||
SPACEMIT_LCR_LV_STANDARD_MASK : SPACEMIT_LCR_LV_FAST_MASK;
|
||||
|
||||
lcr = readl(i2c->base + SPACEMIT_ILCR);
|
||||
lcr &= ~mask;
|
||||
lcr |= field_prep(mask, lv);
|
||||
writel(lcr, i2c->base + SPACEMIT_ILCR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spacemit_i2c_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
|
||||
u32 lv, offset;
|
||||
|
||||
lv = spacemit_i2c_calc_lv(i2c, req->best_parent_rate, req->rate);
|
||||
offset = (i2c->mode == SPACEMIT_MODE_STANDARD) ? 8 : 10;
|
||||
req->rate = DIV_ROUND_CLOSEST(req->best_parent_rate, lv * 2 + offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long spacemit_i2c_clk_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
|
||||
u32 lcr, lv = 0;
|
||||
|
||||
lcr = readl(i2c->base + SPACEMIT_ILCR);
|
||||
|
||||
if (i2c->mode == SPACEMIT_MODE_STANDARD) {
|
||||
lv = FIELD_GET(SPACEMIT_LCR_LV_STANDARD_MASK, lcr);
|
||||
return DIV_ROUND_CLOSEST(parent_rate, lv * 2 + 8);
|
||||
}
|
||||
|
||||
lv = FIELD_GET(SPACEMIT_LCR_LV_FAST_MASK, lcr);
|
||||
return DIV_ROUND_CLOSEST(parent_rate, lv * 2 + 10);
|
||||
}
|
||||
|
||||
static const struct clk_ops spacemit_i2c_clk_ops = {
|
||||
.set_rate = spacemit_i2c_clk_set_rate,
|
||||
.determine_rate = spacemit_i2c_clk_determine_rate,
|
||||
.recalc_rate = spacemit_i2c_clk_recalc_rate,
|
||||
};
|
||||
|
||||
static void spacemit_i2c_enable(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
u32 val;
|
||||
@@ -153,6 +255,28 @@ static void spacemit_i2c_disable(struct spacemit_i2c_dev *i2c)
|
||||
writel(val, i2c->base + SPACEMIT_ICR);
|
||||
}
|
||||
|
||||
static int spacemit_i2c_register_scl_clk(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
struct clk_init_data init = {};
|
||||
char name[64];
|
||||
int ret;
|
||||
|
||||
ret = snprintf(name, sizeof(name), "%s_scl_clk", dev_name(i2c->dev));
|
||||
if (ret >= ARRAY_SIZE(name))
|
||||
dev_warn(i2c->dev, "scl clock name truncated");
|
||||
|
||||
init.name = name;
|
||||
init.ops = &spacemit_i2c_clk_ops;
|
||||
init.parent_data = (struct clk_parent_data[]) {
|
||||
{ .fw_name = "func" },
|
||||
};
|
||||
init.num_parents = 1;
|
||||
|
||||
i2c->scl_clk_hw.init = &init;
|
||||
|
||||
return devm_clk_hw_register(i2c->dev, &i2c->scl_clk_hw);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_reset(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
writel(SPACEMIT_CR_UR, i2c->base + SPACEMIT_ICR);
|
||||
@@ -286,7 +410,7 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
|
||||
val |= SPACEMIT_CR_MSDIE;
|
||||
}
|
||||
|
||||
if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ)
|
||||
if (i2c->mode == SPACEMIT_MODE_FAST)
|
||||
val |= SPACEMIT_CR_MODE_FAST;
|
||||
|
||||
/* disable response to general call */
|
||||
@@ -309,6 +433,14 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
|
||||
writel(val, i2c->base + SPACEMIT_IRCR);
|
||||
|
||||
spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK);
|
||||
|
||||
/*
|
||||
* Initialize IWCR to the value specified by the I2C IP designer.
|
||||
* The SCL frequency formulas (SCL = FCLK / (2*SLV+8) for standard
|
||||
* mode, SCL = FCLK / (2*FLV+10) for fast mode) are only valid when
|
||||
* IWCR contains this specific value.
|
||||
*/
|
||||
writel(SPACEMIT_IWCR_INIT_VALUE, i2c->base + SPACEMIT_IWCR);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)
|
||||
@@ -698,19 +830,18 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
|
||||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq);
|
||||
if (ret && ret != -EINVAL)
|
||||
dev_warn(dev, "failed to read clock-frequency property: %d\n", ret);
|
||||
of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq);
|
||||
|
||||
/* For now, this driver doesn't support high-speed. */
|
||||
if (!i2c->clock_freq || i2c->clock_freq > SPACEMIT_I2C_MAX_FAST_MODE_FREQ) {
|
||||
dev_warn(dev, "unsupported clock frequency %u; using %u\n",
|
||||
i2c->clock_freq, SPACEMIT_I2C_MAX_FAST_MODE_FREQ);
|
||||
i2c->clock_freq = SPACEMIT_I2C_MAX_FAST_MODE_FREQ;
|
||||
} else if (i2c->clock_freq < SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) {
|
||||
dev_warn(dev, "unsupported clock frequency %u; using %u\n",
|
||||
i2c->clock_freq, SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ);
|
||||
i2c->clock_freq = SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ;
|
||||
if (i2c->clock_freq > I2C_MAX_STANDARD_MODE_FREQ &&
|
||||
i2c->clock_freq <= I2C_MAX_FAST_MODE_FREQ) {
|
||||
i2c->mode = SPACEMIT_MODE_FAST;
|
||||
} else if (i2c->clock_freq && i2c->clock_freq <= I2C_MAX_STANDARD_MODE_FREQ) {
|
||||
i2c->mode = SPACEMIT_MODE_STANDARD;
|
||||
} else {
|
||||
dev_info(dev, "clock-frequency not set or out of range, using fast mode\n");
|
||||
i2c->mode = SPACEMIT_MODE_FAST;
|
||||
i2c->clock_freq = I2C_MAX_FAST_MODE_FREQ;
|
||||
}
|
||||
|
||||
i2c->dev = &pdev->dev;
|
||||
@@ -721,12 +852,21 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
i2c->irq = platform_get_irq(pdev, 0);
|
||||
if (i2c->irq < 0)
|
||||
return dev_err_probe(dev, i2c->irq, "failed to get irq resource");
|
||||
return i2c->irq;
|
||||
|
||||
clk = devm_clk_get_enabled(dev, "func");
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock");
|
||||
|
||||
ret = spacemit_i2c_register_scl_clk(i2c);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to register scl clock\n");
|
||||
|
||||
i2c->scl_clk = devm_clk_hw_get_clk(dev, &i2c->scl_clk_hw, "scl");
|
||||
if (IS_ERR(i2c->scl_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(i2c->scl_clk),
|
||||
"failed to get scl clock\n");
|
||||
|
||||
clk = devm_clk_get_enabled(dev, "bus");
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock");
|
||||
@@ -736,6 +876,19 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(dev, PTR_ERR(rst),
|
||||
"failed to acquire deasserted reset\n");
|
||||
|
||||
ret = clk_set_rate(i2c->scl_clk, i2c->clock_freq);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to set rate for SCL clock");
|
||||
|
||||
ret = clk_prepare_enable(i2c->scl_clk);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to prepare and enable clock");
|
||||
|
||||
ret = devm_add_action_or_reset(dev, spacemit_i2c_scl_clk_disable_unprepare,
|
||||
i2c->scl_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spacemit_i2c_reset(i2c);
|
||||
|
||||
i2c_set_adapdata(&i2c->adapt, i2c);
|
||||
@@ -753,7 +906,7 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
|
||||
ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler,
|
||||
IRQF_NO_SUSPEND, dev_name(i2c->dev), i2c);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to request irq");
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
|
||||
@@ -323,7 +323,7 @@ static int ls2x_i2c_probe(struct platform_device *pdev)
|
||||
ret = devm_request_irq(dev, irq, ls2x_i2c_isr, IRQF_SHARED, "ls2x-i2c",
|
||||
priv);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq);
|
||||
return ret;
|
||||
|
||||
return devm_i2c_add_adapter(dev, adap);
|
||||
}
|
||||
|
||||
@@ -565,10 +565,10 @@ static int mchp_corei2c_probe(struct platform_device *pdev)
|
||||
&idev->bus_clk_rate);
|
||||
if (ret || !idev->bus_clk_rate) {
|
||||
dev_info(&pdev->dev, "default to 100kHz\n");
|
||||
idev->bus_clk_rate = 100000;
|
||||
idev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
}
|
||||
|
||||
if (idev->bus_clk_rate > 400000)
|
||||
if (idev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"clock-frequency too high: %d\n",
|
||||
idev->bus_clk_rate);
|
||||
@@ -581,8 +581,7 @@ static int mchp_corei2c_probe(struct platform_device *pdev)
|
||||
ret = devm_request_irq(&pdev->dev, irq, mchp_corei2c_isr, IRQF_SHARED,
|
||||
pdev->name, idev);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"failed to claim irq %d\n", irq);
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(idev->i2c_clk);
|
||||
if (ret)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user