Merge branch 'i2c/for-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wilfram Sang:
 "I2C has the following updates for you:
   - an immutable cross-subsystem branch fixing PMIC access on Intel
     Baytrail
   - bigger driver updates to the designware, meson, exynos5 drivers
   - new i2c_acpi_new_device() function to create devices from ACPI
   - struct i2c_driver has now a flag 'disable_i2c_core_irq_mapping' to
     allow custom IRQ mapping in case the default does not fit
   - mux subsystem centralized error messages in its core
   - new driver for ltc4306 i2c mux
   - usual set of small updates"
* 'i2c/for-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (44 commits)
  i2c: thunderx: Enable HWMON class probing
  i2c: rcar: clarify PM handling with more comments
  i2c: rcar: fix resume by always initializing registers before transfer
  i2c: tegra: fix spelling mistake: "contoller" -> "controller"
  i2c: exynos5: use core helper to get driver data
  i2c: exynos5: de-duplicate error logs on clock setup
  i2c: exynos5: simplify clock frequency handling
  i2c: exynos5: simplify timings calculation
  i2c: designware-baytrail: fix potential null pointer dereference on dev
  i2c: designware: Get selected speed mode sda-hold-time via ACPI
  [media] cx231xx: stop double error reporting
  i2c: core: Allow drivers to disable i2c-core irq mapping
  i2c: core: Add new i2c_acpi_new_device helper function
  i2c: core: Allow getting ACPI info by index
  i2c: img-scb: use setup_timer
  i2c: i2c-scmi: add a MS HID
  i2c: mux: ltc4306: LTC4306 and LTC4305 I2C multiplexer/switch
  dt-bindings: i2c: mux: ltc4306: Add dt-bindings for I2C multiplexer/switch
  i2c: mux: reg: stop double error reporting
  i2c: mux: pinctrl: stop double error reporting
  ...
			
			
This commit is contained in:
		
						commit
						14b730723a
					
				| @ -8,6 +8,8 @@ Required properties: | ||||
|  - #address-cells: should be <1> | ||||
|  - #size-cells: should be <0> | ||||
| 
 | ||||
| For details regarding the following core I2C bindings see also i2c.txt. | ||||
| 
 | ||||
| Optional properties: | ||||
| - clock-frequency: the desired I2C bus clock frequency in Hz; in | ||||
|   absence of this property the default value is used (100 kHz). | ||||
|  | ||||
							
								
								
									
										61
									
								
								Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| * Linear Technology / Analog Devices I2C bus switch | ||||
| 
 | ||||
| Required Properties: | ||||
| 
 | ||||
|   - compatible: Must contain one of the following. | ||||
|     "lltc,ltc4305", "lltc,ltc4306" | ||||
|   - reg: The I2C address of the device. | ||||
| 
 | ||||
|   The following required properties are defined externally: | ||||
| 
 | ||||
|   - Standard I2C mux properties. See i2c-mux.txt in this directory. | ||||
|   - I2C child bus nodes. See i2c-mux.txt in this directory. | ||||
| 
 | ||||
| Optional Properties: | ||||
| 
 | ||||
|   - enable-gpios: Reference to the GPIO connected to the enable input. | ||||
|   - i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all | ||||
|     children in idle state. This is necessary for example, if there are several | ||||
|     multiplexers on the bus and the devices behind them use same I2C addresses. | ||||
|   - gpio-controller: Marks the device node as a GPIO Controller. | ||||
|   - #gpio-cells: Should be two.  The first cell is the pin number and | ||||
| 	the second cell is used to specify flags. | ||||
| 	See ../gpio/gpio.txt for more information. | ||||
|   - ltc,downstream-accelerators-enable: Enables the rise time accelerators | ||||
| 	on the downstream port. | ||||
|   - ltc,upstream-accelerators-enable: Enables the rise time accelerators | ||||
| 	on the upstream port. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| 	ltc4306: i2c-mux@4a { | ||||
| 		compatible = "lltc,ltc4306"; | ||||
| 		#address-cells = <1>; | ||||
| 		#size-cells = <0>; | ||||
| 		reg = <0x4a>; | ||||
| 
 | ||||
| 		gpio-controller; | ||||
| 		#gpio-cells = <2>; | ||||
| 
 | ||||
| 		i2c@0 { | ||||
| 			#address-cells = <1>; | ||||
| 			#size-cells = <0>; | ||||
| 			reg = <0>; | ||||
| 
 | ||||
| 			eeprom@50 { | ||||
| 				compatible = "at,24c02"; | ||||
| 				reg = <0x50>; | ||||
| 			}; | ||||
| 		}; | ||||
| 
 | ||||
| 		i2c@1 { | ||||
| 			#address-cells = <1>; | ||||
| 			#size-cells = <0>; | ||||
| 			reg = <1>; | ||||
| 
 | ||||
| 			eeprom@50 { | ||||
| 				compatible = "at,24c02"; | ||||
| 				reg = <0x50>; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
| @ -11,6 +11,7 @@ Required properties : | ||||
|    - "rockchip,rk3188-i2c": for rk3188 | ||||
|    - "rockchip,rk3228-i2c": for rk3228 | ||||
|    - "rockchip,rk3288-i2c": for rk3288 | ||||
|    - "rockchip,rk3328-i2c", "rockchip,rk3399-i2c": for rk3328 | ||||
|    - "rockchip,rk3399-i2c": for rk3399 | ||||
|  - interrupts : interrupt number | ||||
|  - clocks: See ../clock/clock-bindings.txt | ||||
|  | ||||
| @ -7775,6 +7775,14 @@ S:	Maintained | ||||
| F:	Documentation/hwmon/ltc4261 | ||||
| F:	drivers/hwmon/ltc4261.c | ||||
| 
 | ||||
| LTC4306 I2C MULTIPLEXER DRIVER | ||||
| M:	Michael Hennerich <michael.hennerich@analog.com> | ||||
| W:	http://ez.analog.com/community/linux-device-drivers | ||||
| L:	linux-i2c@vger.kernel.org | ||||
| S:	Supported | ||||
| F:	drivers/i2c/muxes/i2c-mux-ltc4306.c | ||||
| F:	Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt | ||||
| 
 | ||||
| LTP (Linux Test Project) | ||||
| M:	Mike Frysinger <vapier@gentoo.org> | ||||
| M:	Cyril Hrubis <chrubis@suse.cz> | ||||
|  | ||||
| @ -933,6 +933,7 @@ config I2C_TEGRA | ||||
| config I2C_TEGRA_BPMP | ||||
| 	tristate "NVIDIA Tegra BPMP I2C controller" | ||||
| 	depends on TEGRA_BPMP | ||||
| 	default y | ||||
| 	help | ||||
| 	  If you say yes to this option, support will be included for the I2C | ||||
| 	  controller embedded in NVIDIA Tegra SoCs accessed via the BPMP. | ||||
| @ -1021,7 +1022,7 @@ config I2C_XLR | ||||
| 
 | ||||
| config I2C_XLP9XX | ||||
| 	tristate "XLP9XX I2C support" | ||||
| 	depends on CPU_XLP || ARCH_VULCAN || COMPILE_TEST | ||||
| 	depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST | ||||
| 	help | ||||
| 	  This driver enables support for the on-chip I2C interface of | ||||
| 	  the Broadcom XLP9xx/XLP5xx MIPS and Vulcan ARM64 processors. | ||||
|  | ||||
| @ -22,7 +22,7 @@ | ||||
| 
 | ||||
| #include "i2c-designware-core.h" | ||||
| 
 | ||||
| #define SEMAPHORE_TIMEOUT	100 | ||||
| #define SEMAPHORE_TIMEOUT	500 | ||||
| #define PUNIT_SEMAPHORE		0x7 | ||||
| #define PUNIT_SEMAPHORE_CHT	0x10e | ||||
| #define PUNIT_SEMAPHORE_BIT	BIT(0) | ||||
| @ -70,7 +70,7 @@ static void reset_semaphore(struct dw_i2c_dev *dev) | ||||
| 
 | ||||
| static int baytrail_i2c_acquire(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	u32 addr = get_sem_addr(dev); | ||||
| 	u32 addr; | ||||
| 	u32 sem = PUNIT_SEMAPHORE_ACQUIRE; | ||||
| 	int ret; | ||||
| 	unsigned long start, end; | ||||
| @ -94,6 +94,8 @@ static int baytrail_i2c_acquire(struct dw_i2c_dev *dev) | ||||
| 	 */ | ||||
| 	pm_qos_update_request(&dev->pm_qos, 0); | ||||
| 
 | ||||
| 	addr = get_sem_addr(dev); | ||||
| 
 | ||||
| 	/* host driver writes to side band semaphore register */ | ||||
| 	ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, addr, sem); | ||||
| 	if (ret) { | ||||
| @ -170,7 +172,7 @@ int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) | ||||
| 	dev_info(dev->dev, "I2C bus managed by PUNIT\n"); | ||||
| 	dev->acquire_lock = baytrail_i2c_acquire; | ||||
| 	dev->release_lock = baytrail_i2c_release; | ||||
| 	dev->pm_runtime_disabled = true; | ||||
| 	dev->pm_disabled = true; | ||||
| 
 | ||||
| 	pm_qos_add_request(&dev->pm_qos, PM_QOS_CPU_DMA_LATENCY, | ||||
| 			   PM_QOS_DEFAULT_VALUE); | ||||
|  | ||||
| @ -960,6 +960,7 @@ EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param); | ||||
| int i2c_dw_probe(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	struct i2c_adapter *adap = &dev->adapter; | ||||
| 	unsigned long irq_flags; | ||||
| 	int r; | ||||
| 
 | ||||
| 	init_completion(&dev->cmd_complete); | ||||
| @ -975,9 +976,15 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) | ||||
| 	adap->dev.parent = dev->dev; | ||||
| 	i2c_set_adapdata(adap, dev); | ||||
| 
 | ||||
| 	if (dev->pm_disabled) { | ||||
| 		dev_pm_syscore_device(dev->dev, true); | ||||
| 		irq_flags = IRQF_NO_SUSPEND; | ||||
| 	} else { | ||||
| 		irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND; | ||||
| 	} | ||||
| 
 | ||||
| 	i2c_dw_disable_int(dev); | ||||
| 	r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, | ||||
| 			     IRQF_SHARED | IRQF_COND_SUSPEND, | ||||
| 	r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags, | ||||
| 			     dev_name(dev->dev), dev); | ||||
| 	if (r) { | ||||
| 		dev_err(dev->dev, "failure requesting irq %i: %d\n", | ||||
|  | ||||
| @ -79,7 +79,7 @@ | ||||
|  * @pm_qos: pm_qos_request used while holding a hardware lock on the bus | ||||
|  * @acquire_lock: function to acquire a hardware lock on the bus | ||||
|  * @release_lock: function to release a hardware lock on the bus | ||||
|  * @pm_runtime_disabled: true if pm runtime is disabled | ||||
|  * @pm_disabled: true if power-management should be disabled for this i2c-bus | ||||
|  * | ||||
|  * HCNT and LCNT parameters can be used if the platform knows more accurate | ||||
|  * values than the one computed based only on the input clock frequency. | ||||
| @ -128,7 +128,7 @@ struct dw_i2c_dev { | ||||
| 	struct pm_qos_request	pm_qos; | ||||
| 	int			(*acquire_lock)(struct dw_i2c_dev *dev); | ||||
| 	void			(*release_lock)(struct dw_i2c_dev *dev); | ||||
| 	bool			pm_runtime_disabled; | ||||
| 	bool			pm_disabled; | ||||
| }; | ||||
| 
 | ||||
| #define ACCESS_SWAP		0x00000001 | ||||
|  | ||||
| @ -85,8 +85,7 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[], | ||||
| 
 | ||||
| 		*hcnt = (u16)objs[0].integer.value; | ||||
| 		*lcnt = (u16)objs[1].integer.value; | ||||
| 		if (sda_hold) | ||||
| 			*sda_hold = (u32)objs[2].integer.value; | ||||
| 		*sda_hold = (u32)objs[2].integer.value; | ||||
| 	} | ||||
| 
 | ||||
| 	kfree(buf.pointer); | ||||
| @ -95,26 +94,55 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[], | ||||
| static int dw_i2c_acpi_configure(struct platform_device *pdev) | ||||
| { | ||||
| 	struct dw_i2c_dev *dev = platform_get_drvdata(pdev); | ||||
| 	acpi_handle handle = ACPI_HANDLE(&pdev->dev); | ||||
| 	const struct acpi_device_id *id; | ||||
| 	struct acpi_device *adev; | ||||
| 	const char *uid; | ||||
| 
 | ||||
| 	dev->adapter.nr = -1; | ||||
| 	dev->tx_fifo_depth = 32; | ||||
| 	dev->rx_fifo_depth = 32; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Try to get SDA hold time and *CNT values from an ACPI method if | ||||
| 	 * it exists for both supported speed modes. | ||||
| 	 * Try to get SDA hold time and *CNT values from an ACPI method for | ||||
| 	 * selected speed modes. | ||||
| 	 */ | ||||
| 	dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, NULL); | ||||
| 	dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, | ||||
| 			   &dev->sda_hold_time); | ||||
| 	dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, NULL); | ||||
| 	dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, NULL); | ||||
| 	switch (dev->clk_freq) { | ||||
| 	case 100000: | ||||
| 		dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, | ||||
| 				   &dev->sda_hold_time); | ||||
| 		break; | ||||
| 	case 1000000: | ||||
| 		dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, | ||||
| 				   &dev->sda_hold_time); | ||||
| 		break; | ||||
| 	case 3400000: | ||||
| 		dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, | ||||
| 				   &dev->sda_hold_time); | ||||
| 		break; | ||||
| 	case 400000: | ||||
| 	default: | ||||
| 		dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, | ||||
| 				   &dev->sda_hold_time); | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); | ||||
| 	if (id && id->driver_data) | ||||
| 		dev->flags |= (u32)id->driver_data; | ||||
| 
 | ||||
| 	if (acpi_bus_get_device(handle, &adev)) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Cherrytrail I2C7 gets used for the PMIC which gets accessed | ||||
| 	 * through ACPI opregions during late suspend / early resume | ||||
| 	 * disable pm for it. | ||||
| 	 */ | ||||
| 	uid = adev->pnp.unique_id; | ||||
| 	if ((dev->flags & MODEL_CHERRYTRAIL) && !strcmp(uid, "7")) | ||||
| 		dev->pm_disabled = true; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -286,7 +314,7 @@ 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_runtime_disabled) { | ||||
| 	if (dev->pm_disabled) { | ||||
| 		pm_runtime_forbid(&pdev->dev); | ||||
| 	} else { | ||||
| 		pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); | ||||
| @ -302,7 +330,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) | ||||
| 	return r; | ||||
| 
 | ||||
| exit_probe: | ||||
| 	if (!dev->pm_runtime_disabled) | ||||
| 	if (!dev->pm_disabled) | ||||
| 		pm_runtime_disable(&pdev->dev); | ||||
| exit_reset: | ||||
| 	if (!IS_ERR_OR_NULL(dev->rst)) | ||||
| @ -322,7 +350,7 @@ 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_runtime_disabled) | ||||
| 	if (!dev->pm_disabled) | ||||
| 		pm_runtime_disable(&pdev->dev); | ||||
| 	if (!IS_ERR_OR_NULL(dev->rst)) | ||||
| 		reset_control_assert(dev->rst); | ||||
| @ -374,9 +402,7 @@ static int dw_i2c_plat_resume(struct device *dev) | ||||
| 	struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); | ||||
| 
 | ||||
| 	i2c_dw_plat_prepare_clk(i_dev, true); | ||||
| 
 | ||||
| 	if (!i_dev->pm_runtime_disabled) | ||||
| 		i2c_dw_init(i_dev); | ||||
| 	i2c_dw_init(i_dev); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @ -22,6 +22,7 @@ | ||||
| #include <linux/slab.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/of_address.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/of_irq.h> | ||||
| #include <linux/spinlock.h> | ||||
| 
 | ||||
| @ -168,8 +169,6 @@ | ||||
|  */ | ||||
| #define HSI2C_HS_TX_CLOCK	1000000 | ||||
| #define HSI2C_FS_TX_CLOCK	100000 | ||||
| #define HSI2C_HIGH_SPD		1 | ||||
| #define HSI2C_FAST_SPD		0 | ||||
| 
 | ||||
| #define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000)) | ||||
| 
 | ||||
| @ -200,18 +199,10 @@ struct exynos5_i2c { | ||||
| 	int			trans_done; | ||||
| 
 | ||||
| 	/* Controller operating frequency */ | ||||
| 	unsigned int		fs_clock; | ||||
| 	unsigned int		hs_clock; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * HSI2C Controller can operate in | ||||
| 	 * 1. High speed upto 3.4Mbps | ||||
| 	 * 2. Fast speed upto 1Mbps | ||||
| 	 */ | ||||
| 	int			speed_mode; | ||||
| 	unsigned int		op_clock; | ||||
| 
 | ||||
| 	/* Version of HS-I2C Hardware */ | ||||
| 	struct exynos_hsi2c_variant	*variant; | ||||
| 	const struct exynos_hsi2c_variant *variant; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -257,15 +248,6 @@ static const struct of_device_id exynos5_i2c_match[] = { | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, exynos5_i2c_match); | ||||
| 
 | ||||
| static inline struct exynos_hsi2c_variant *exynos5_i2c_get_variant | ||||
| 					(struct platform_device *pdev) | ||||
| { | ||||
| 	const struct of_device_id *match; | ||||
| 
 | ||||
| 	match = of_match_node(exynos5_i2c_match, pdev->dev.of_node); | ||||
| 	return (struct exynos_hsi2c_variant *)match->data; | ||||
| } | ||||
| 
 | ||||
| static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c) | ||||
| { | ||||
| 	writel(readl(i2c->regs + HSI2C_INT_STATUS), | ||||
| @ -279,7 +261,7 @@ static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c) | ||||
|  * Returns 0 on success, -EINVAL if the cycle length cannot | ||||
|  * be calculated. | ||||
|  */ | ||||
| static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) | ||||
| static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) | ||||
| { | ||||
| 	u32 i2c_timing_s1; | ||||
| 	u32 i2c_timing_s2; | ||||
| @ -292,9 +274,10 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) | ||||
| 	unsigned int t_sr_release; | ||||
| 	unsigned int t_ftl_cycle; | ||||
| 	unsigned int clkin = clk_get_rate(i2c->clk); | ||||
| 	unsigned int div, utemp0 = 0, utemp1 = 0, clk_cycle; | ||||
| 	unsigned int op_clk = (mode == HSI2C_HIGH_SPD) ? | ||||
| 				i2c->hs_clock : i2c->fs_clock; | ||||
| 	unsigned int op_clk = hs_timings ? i2c->op_clock : | ||||
| 		(i2c->op_clock >= HSI2C_HS_TX_CLOCK) ? HSI2C_FS_TX_CLOCK : | ||||
| 		i2c->op_clock; | ||||
| 	int div, clk_cycle, temp; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * In case of HSI2C controller in Exynos5 series | ||||
| @ -305,33 +288,22 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) | ||||
| 	 * FPCLK / FI2C = | ||||
| 	 * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + FLT_CYCLE | ||||
| 	 * | ||||
| 	 * utemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) | ||||
| 	 * utemp1 = (TSCLK_L + TSCLK_H + 2) | ||||
| 	 * clk_cycle := TSCLK_L + TSCLK_H | ||||
| 	 * temp := (CLK_DIV + 1) * (clk_cycle + 2) | ||||
| 	 * | ||||
| 	 * Constraints: 4 <= temp, 0 <= CLK_DIV < 256, 2 <= clk_cycle <= 510 | ||||
| 	 * | ||||
| 	 */ | ||||
| 	t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; | ||||
| 	utemp0 = (clkin / op_clk) - 8; | ||||
| 
 | ||||
| 	if (i2c->variant->hw == HSI2C_EXYNOS7) | ||||
| 		utemp0 -= t_ftl_cycle; | ||||
| 	else | ||||
| 		utemp0 -= 2 * t_ftl_cycle; | ||||
| 
 | ||||
| 	/* CLK_DIV max is 256 */ | ||||
| 	for (div = 0; div < 256; div++) { | ||||
| 		utemp1 = utemp0 / (div + 1); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * SCL_L and SCL_H each has max value of 255 | ||||
| 		 * Hence, For the clk_cycle to the have right value | ||||
| 		 * utemp1 has to be less then 512 and more than 4. | ||||
| 		 */ | ||||
| 		if ((utemp1 < 512) && (utemp1 > 4)) { | ||||
| 			clk_cycle = utemp1 - 2; | ||||
| 			break; | ||||
| 		} else if (div == 255) { | ||||
| 			dev_warn(i2c->dev, "Failed to calculate divisor"); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 	temp = clkin / op_clk - 8 - t_ftl_cycle; | ||||
| 	if (i2c->variant->hw != HSI2C_EXYNOS7) | ||||
| 		temp -= t_ftl_cycle; | ||||
| 	div = temp / 512; | ||||
| 	clk_cycle = temp / (div + 1) - 2; | ||||
| 	if (temp < 4 || div >= 256 || clk_cycle < 2) { | ||||
| 		dev_err(i2c->dev, "%s clock set-up failed\n", | ||||
| 			hs_timings ? "HS" : "FS"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	t_scl_l = clk_cycle / 2; | ||||
| @ -356,7 +328,7 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) | ||||
| 		div, t_sr_release); | ||||
| 	dev_dbg(i2c->dev, "tDATA_HD: %X\n", t_data_hd); | ||||
| 
 | ||||
| 	if (mode == HSI2C_HIGH_SPD) { | ||||
| 	if (hs_timings) { | ||||
| 		writel(i2c_timing_s1, i2c->regs + HSI2C_TIMING_HS1); | ||||
| 		writel(i2c_timing_s2, i2c->regs + HSI2C_TIMING_HS2); | ||||
| 		writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3); | ||||
| @ -372,24 +344,13 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) | ||||
| 
 | ||||
| static int exynos5_hsi2c_clock_setup(struct exynos5_i2c *i2c) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * Configure the Fast speed timing values | ||||
| 	 * Even the High Speed mode initially starts with Fast mode | ||||
| 	 */ | ||||
| 	if (exynos5_i2c_set_timing(i2c, HSI2C_FAST_SPD)) { | ||||
| 		dev_err(i2c->dev, "HSI2C FS Clock set up failed\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	/* always set Fast Speed timings */ | ||||
| 	int ret = exynos5_i2c_set_timing(i2c, false); | ||||
| 
 | ||||
| 	/* configure the High speed timing values */ | ||||
| 	if (i2c->speed_mode == HSI2C_HIGH_SPD) { | ||||
| 		if (exynos5_i2c_set_timing(i2c, HSI2C_HIGH_SPD)) { | ||||
| 			dev_err(i2c->dev, "HSI2C HS Clock set up failed\n"); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 	} | ||||
| 	if (ret < 0 || i2c->op_clock < HSI2C_HS_TX_CLOCK) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	return 0; | ||||
| 	return exynos5_i2c_set_timing(i2c, true); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -409,7 +370,7 @@ static void exynos5_i2c_init(struct exynos5_i2c *i2c) | ||||
| 					i2c->regs + HSI2C_CTL); | ||||
| 	writel(HSI2C_TRAILING_COUNT, i2c->regs + HSI2C_TRAILIG_CTL); | ||||
| 
 | ||||
| 	if (i2c->speed_mode == HSI2C_HIGH_SPD) { | ||||
| 	if (i2c->op_clock >= HSI2C_HS_TX_CLOCK) { | ||||
| 		writel(HSI2C_MASTER_ID(MASTER_ID(i2c->adap.nr)), | ||||
| 					i2c->regs + HSI2C_ADDR); | ||||
| 		i2c_conf |= HSI2C_HS_MODE; | ||||
| @ -747,26 +708,14 @@ static int exynos5_i2c_probe(struct platform_device *pdev) | ||||
| 	struct device_node *np = pdev->dev.of_node; | ||||
| 	struct exynos5_i2c *i2c; | ||||
| 	struct resource *mem; | ||||
| 	unsigned int op_clock; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL); | ||||
| 	if (!i2c) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	if (of_property_read_u32(np, "clock-frequency", &op_clock)) { | ||||
| 		i2c->speed_mode = HSI2C_FAST_SPD; | ||||
| 		i2c->fs_clock = HSI2C_FS_TX_CLOCK; | ||||
| 	} else { | ||||
| 		if (op_clock >= HSI2C_HS_TX_CLOCK) { | ||||
| 			i2c->speed_mode = HSI2C_HIGH_SPD; | ||||
| 			i2c->fs_clock = HSI2C_FS_TX_CLOCK; | ||||
| 			i2c->hs_clock = op_clock; | ||||
| 		} else { | ||||
| 			i2c->speed_mode = HSI2C_FAST_SPD; | ||||
| 			i2c->fs_clock = op_clock; | ||||
| 		} | ||||
| 	} | ||||
| 	if (of_property_read_u32(np, "clock-frequency", &i2c->op_clock)) | ||||
| 		i2c->op_clock = HSI2C_FS_TX_CLOCK; | ||||
| 
 | ||||
| 	strlcpy(i2c->adap.name, "exynos5-i2c", sizeof(i2c->adap.name)); | ||||
| 	i2c->adap.owner   = THIS_MODULE; | ||||
| @ -817,8 +766,7 @@ static int exynos5_i2c_probe(struct platform_device *pdev) | ||||
| 		goto err_clk; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Need to check the variant before setting up. */ | ||||
| 	i2c->variant = exynos5_i2c_get_variant(pdev); | ||||
| 	i2c->variant = of_device_get_match_data(&pdev->dev); | ||||
| 
 | ||||
| 	ret = exynos5_hsi2c_clock_setup(i2c); | ||||
| 	if (ret) | ||||
|  | ||||
| @ -1362,9 +1362,8 @@ static int img_i2c_probe(struct platform_device *pdev) | ||||
| 	} | ||||
| 
 | ||||
| 	/* Set up the exception check timer */ | ||||
| 	init_timer(&i2c->check_timer); | ||||
| 	i2c->check_timer.function = img_i2c_check_timer; | ||||
| 	i2c->check_timer.data = (unsigned long)i2c; | ||||
| 	setup_timer(&i2c->check_timer, img_i2c_check_timer, | ||||
| 		    (unsigned long)i2c); | ||||
| 
 | ||||
| 	i2c->bitrate = timings[0].max_bitrate; | ||||
| 	if (!of_property_read_u32(node, "clock-frequency", &val)) | ||||
|  | ||||
| @ -35,10 +35,11 @@ | ||||
| #define REG_CTRL_STATUS		BIT(2) | ||||
| #define REG_CTRL_ERROR		BIT(3) | ||||
| #define REG_CTRL_CLKDIV_SHIFT	12 | ||||
| #define REG_CTRL_CLKDIV_MASK	((BIT(10) - 1) << REG_CTRL_CLKDIV_SHIFT) | ||||
| #define REG_CTRL_CLKDIV_MASK	GENMASK(21, 12) | ||||
| #define REG_CTRL_CLKDIVEXT_SHIFT 28 | ||||
| #define REG_CTRL_CLKDIVEXT_MASK	GENMASK(29, 28) | ||||
| 
 | ||||
| #define I2C_TIMEOUT_MS		500 | ||||
| #define DEFAULT_FREQ		100000 | ||||
| 
 | ||||
| enum { | ||||
| 	TOKEN_END = 0, | ||||
| @ -54,7 +55,6 @@ enum { | ||||
| 	STATE_IDLE, | ||||
| 	STATE_READ, | ||||
| 	STATE_WRITE, | ||||
| 	STATE_STOP, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -73,7 +73,6 @@ enum { | ||||
|  * @error:	Flag set when an error is received | ||||
|  * @lock:	To avoid race conditions between irq handler and xfer code | ||||
|  * @done:	Completion used to wait for transfer termination | ||||
|  * @frequency:	Operating frequency of I2C bus clock | ||||
|  * @tokens:	Sequence of tokens to be written to the device | ||||
|  * @num_tokens:	Number of tokens | ||||
|  */ | ||||
| @ -82,7 +81,6 @@ struct meson_i2c { | ||||
| 	struct device		*dev; | ||||
| 	void __iomem		*regs; | ||||
| 	struct clk		*clk; | ||||
| 	int			irq; | ||||
| 
 | ||||
| 	struct i2c_msg		*msg; | ||||
| 	int			state; | ||||
| @ -93,7 +91,6 @@ struct meson_i2c { | ||||
| 
 | ||||
| 	spinlock_t		lock; | ||||
| 	struct completion	done; | ||||
| 	unsigned int		frequency; | ||||
| 	u32			tokens[2]; | ||||
| 	int			num_tokens; | ||||
| }; | ||||
| @ -126,23 +123,27 @@ static void meson_i2c_add_token(struct meson_i2c *i2c, int token) | ||||
| 	i2c->num_tokens++; | ||||
| } | ||||
| 
 | ||||
| static void meson_i2c_write_tokens(struct meson_i2c *i2c) | ||||
| { | ||||
| 	writel(i2c->tokens[0], i2c->regs + REG_TOK_LIST0); | ||||
| 	writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1); | ||||
| } | ||||
| 
 | ||||
| static void meson_i2c_set_clk_div(struct meson_i2c *i2c) | ||||
| static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq) | ||||
| { | ||||
| 	unsigned long clk_rate = clk_get_rate(i2c->clk); | ||||
| 	unsigned int div; | ||||
| 
 | ||||
| 	div = DIV_ROUND_UP(clk_rate, i2c->frequency * 4); | ||||
| 	div = DIV_ROUND_UP(clk_rate, freq * 4); | ||||
| 
 | ||||
| 	/* clock divider has 12 bits */ | ||||
| 	if (div >= (1 << 12)) { | ||||
| 		dev_err(i2c->dev, "requested bus frequency too low\n"); | ||||
| 		div = (1 << 12) - 1; | ||||
| 	} | ||||
| 
 | ||||
| 	meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK, | ||||
| 			   div << REG_CTRL_CLKDIV_SHIFT); | ||||
| 			   (div & GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT); | ||||
| 
 | ||||
| 	meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK, | ||||
| 			   (div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT); | ||||
| 
 | ||||
| 	dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__, | ||||
| 		clk_rate, i2c->frequency, div); | ||||
| 		clk_rate, freq, div); | ||||
| } | ||||
| 
 | ||||
| static void meson_i2c_get_data(struct meson_i2c *i2c, char *buf, int len) | ||||
| @ -156,10 +157,10 @@ static void meson_i2c_get_data(struct meson_i2c *i2c, char *buf, int len) | ||||
| 	dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__, | ||||
| 		rdata0, rdata1, len); | ||||
| 
 | ||||
| 	for (i = 0; i < min_t(int, 4, len); i++) | ||||
| 	for (i = 0; i < min(4, len); i++) | ||||
| 		*buf++ = (rdata0 >> i * 8) & 0xff; | ||||
| 
 | ||||
| 	for (i = 4; i < min_t(int, 8, len); i++) | ||||
| 	for (i = 4; i < min(8, len); i++) | ||||
| 		*buf++ = (rdata1 >> (i - 4) * 8) & 0xff; | ||||
| } | ||||
| 
 | ||||
| @ -168,10 +169,10 @@ static void meson_i2c_put_data(struct meson_i2c *i2c, char *buf, int len) | ||||
| 	u32 wdata0 = 0, wdata1 = 0; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < min_t(int, 4, len); i++) | ||||
| 	for (i = 0; i < min(4, len); i++) | ||||
| 		wdata0 |= *buf++ << (i * 8); | ||||
| 
 | ||||
| 	for (i = 4; i < min_t(int, 8, len); i++) | ||||
| 	for (i = 4; i < min(8, len); i++) | ||||
| 		wdata1 |= *buf++ << ((i - 4) * 8); | ||||
| 
 | ||||
| 	writel(wdata0, i2c->regs + REG_TOK_WDATA0); | ||||
| @ -186,7 +187,7 @@ static void meson_i2c_prepare_xfer(struct meson_i2c *i2c) | ||||
| 	bool write = !(i2c->msg->flags & I2C_M_RD); | ||||
| 	int i; | ||||
| 
 | ||||
| 	i2c->count = min_t(int, i2c->msg->len - i2c->pos, 8); | ||||
| 	i2c->count = min(i2c->msg->len - i2c->pos, 8); | ||||
| 
 | ||||
| 	for (i = 0; i < i2c->count - 1; i++) | ||||
| 		meson_i2c_add_token(i2c, TOKEN_DATA); | ||||
| @ -200,19 +201,12 @@ static void meson_i2c_prepare_xfer(struct meson_i2c *i2c) | ||||
| 
 | ||||
| 	if (write) | ||||
| 		meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count); | ||||
| } | ||||
| 
 | ||||
| static void meson_i2c_stop(struct meson_i2c *i2c) | ||||
| { | ||||
| 	dev_dbg(i2c->dev, "%s: last %d\n", __func__, i2c->last); | ||||
| 
 | ||||
| 	if (i2c->last) { | ||||
| 		i2c->state = STATE_STOP; | ||||
| 	if (i2c->last && i2c->pos + i2c->count >= i2c->msg->len) | ||||
| 		meson_i2c_add_token(i2c, TOKEN_STOP); | ||||
| 	} else { | ||||
| 		i2c->state = STATE_IDLE; | ||||
| 		complete(&i2c->done); | ||||
| 	} | ||||
| 
 | ||||
| 	writel(i2c->tokens[0], i2c->regs + REG_TOK_LIST0); | ||||
| 	writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1); | ||||
| } | ||||
| 
 | ||||
| static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) | ||||
| @ -223,12 +217,18 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) | ||||
| 	spin_lock(&i2c->lock); | ||||
| 
 | ||||
| 	meson_i2c_reset_tokens(i2c); | ||||
| 	meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); | ||||
| 	ctrl = readl(i2c->regs + REG_CTRL); | ||||
| 
 | ||||
| 	dev_dbg(i2c->dev, "irq: state %d, pos %d, count %d, ctrl %08x\n", | ||||
| 		i2c->state, i2c->pos, i2c->count, ctrl); | ||||
| 
 | ||||
| 	if (ctrl & REG_CTRL_ERROR && i2c->state != STATE_IDLE) { | ||||
| 	if (i2c->state == STATE_IDLE) { | ||||
| 		spin_unlock(&i2c->lock); | ||||
| 		return IRQ_NONE; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ctrl & REG_CTRL_ERROR) { | ||||
| 		/*
 | ||||
| 		 * The bit is set when the IGNORE_NAK bit is cleared | ||||
| 		 * and the device didn't respond. In this case, the | ||||
| @ -242,48 +242,21 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (i2c->state) { | ||||
| 	case STATE_READ: | ||||
| 		if (i2c->count > 0) { | ||||
| 			meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, | ||||
| 					   i2c->count); | ||||
| 			i2c->pos += i2c->count; | ||||
| 		} | ||||
| 	if (i2c->state == STATE_READ && i2c->count) | ||||
| 		meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, i2c->count); | ||||
| 
 | ||||
| 		if (i2c->pos >= i2c->msg->len) { | ||||
| 			meson_i2c_stop(i2c); | ||||
| 			break; | ||||
| 		} | ||||
| 	i2c->pos += i2c->count; | ||||
| 
 | ||||
| 		meson_i2c_prepare_xfer(i2c); | ||||
| 		break; | ||||
| 	case STATE_WRITE: | ||||
| 		i2c->pos += i2c->count; | ||||
| 
 | ||||
| 		if (i2c->pos >= i2c->msg->len) { | ||||
| 			meson_i2c_stop(i2c); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		meson_i2c_prepare_xfer(i2c); | ||||
| 		break; | ||||
| 	case STATE_STOP: | ||||
| 	if (i2c->pos >= i2c->msg->len) { | ||||
| 		i2c->state = STATE_IDLE; | ||||
| 		complete(&i2c->done); | ||||
| 		break; | ||||
| 	case STATE_IDLE: | ||||
| 		break; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Restart the processing */ | ||||
| 	meson_i2c_prepare_xfer(i2c); | ||||
| 	meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START); | ||||
| out: | ||||
| 	if (i2c->state != STATE_IDLE) { | ||||
| 		/* Restart the processing */ | ||||
| 		meson_i2c_write_tokens(i2c); | ||||
| 		meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); | ||||
| 		meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, | ||||
| 				   REG_CTRL_START); | ||||
| 	} | ||||
| 
 | ||||
| 	spin_unlock(&i2c->lock); | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| @ -323,7 +296,6 @@ static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg, | ||||
| 
 | ||||
| 	i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; | ||||
| 	meson_i2c_prepare_xfer(i2c); | ||||
| 	meson_i2c_write_tokens(i2c); | ||||
| 	reinit_completion(&i2c->done); | ||||
| 
 | ||||
| 	/* Start the transfer */ | ||||
| @ -359,21 +331,19 @@ static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, | ||||
| 			  int num) | ||||
| { | ||||
| 	struct meson_i2c *i2c = adap->algo_data; | ||||
| 	int i, ret = 0, count = 0; | ||||
| 	int i, ret = 0; | ||||
| 
 | ||||
| 	clk_enable(i2c->clk); | ||||
| 	meson_i2c_set_clk_div(i2c); | ||||
| 
 | ||||
| 	for (i = 0; i < num; i++) { | ||||
| 		ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1); | ||||
| 		if (ret) | ||||
| 			break; | ||||
| 		count++; | ||||
| 	} | ||||
| 
 | ||||
| 	clk_disable(i2c->clk); | ||||
| 
 | ||||
| 	return ret ? ret : count; | ||||
| 	return ret ?: i; | ||||
| } | ||||
| 
 | ||||
| static u32 meson_i2c_func(struct i2c_adapter *adap) | ||||
| @ -391,15 +361,14 @@ static int meson_i2c_probe(struct platform_device *pdev) | ||||
| 	struct device_node *np = pdev->dev.of_node; | ||||
| 	struct meson_i2c *i2c; | ||||
| 	struct resource *mem; | ||||
| 	int ret = 0; | ||||
| 	struct i2c_timings timings; | ||||
| 	int irq, ret = 0; | ||||
| 
 | ||||
| 	i2c = devm_kzalloc(&pdev->dev, sizeof(struct meson_i2c), GFP_KERNEL); | ||||
| 	if (!i2c) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", | ||||
| 				 &i2c->frequency)) | ||||
| 		i2c->frequency = DEFAULT_FREQ; | ||||
| 	i2c_parse_fw_timings(&pdev->dev, &timings, true); | ||||
| 
 | ||||
| 	i2c->dev = &pdev->dev; | ||||
| 	platform_set_drvdata(pdev, i2c); | ||||
| @ -418,14 +387,13 @@ static int meson_i2c_probe(struct platform_device *pdev) | ||||
| 	if (IS_ERR(i2c->regs)) | ||||
| 		return PTR_ERR(i2c->regs); | ||||
| 
 | ||||
| 	i2c->irq = platform_get_irq(pdev, 0); | ||||
| 	if (i2c->irq < 0) { | ||||
| 	irq = platform_get_irq(pdev, 0); | ||||
| 	if (irq < 0) { | ||||
| 		dev_err(&pdev->dev, "can't find IRQ\n"); | ||||
| 		return i2c->irq; | ||||
| 		return irq; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = devm_request_irq(&pdev->dev, i2c->irq, meson_i2c_irq, | ||||
| 			       0, dev_name(&pdev->dev), i2c); | ||||
| 	ret = devm_request_irq(&pdev->dev, irq, meson_i2c_irq, 0, NULL, i2c); | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(&pdev->dev, "can't request IRQ\n"); | ||||
| 		return ret; | ||||
| @ -457,6 +425,8 @@ static int meson_i2c_probe(struct platform_device *pdev) | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	meson_i2c_set_clk_div(i2c, timings.bus_freq_hz); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -823,13 +823,10 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, | ||||
| 
 | ||||
| 	drv_data->rstc = devm_reset_control_get_optional(dev, NULL); | ||||
| 	if (IS_ERR(drv_data->rstc)) { | ||||
| 		if (PTR_ERR(drv_data->rstc) == -EPROBE_DEFER) { | ||||
| 			rc = -EPROBE_DEFER; | ||||
| 			goto out; | ||||
| 		} | ||||
| 	} else { | ||||
| 		reset_control_deassert(drv_data->rstc); | ||||
| 		rc = PTR_ERR(drv_data->rstc); | ||||
| 		goto out; | ||||
| 	} | ||||
| 	reset_control_deassert(drv_data->rstc); | ||||
| 
 | ||||
| 	/* Its not yet defined how timeouts will be specified in device tree.
 | ||||
| 	 * So hard code the value to 1 second. | ||||
| @ -951,8 +948,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) | ||||
| exit_free_irq: | ||||
| 	free_irq(drv_data->irq, drv_data); | ||||
| exit_reset: | ||||
| 	if (!IS_ERR_OR_NULL(drv_data->rstc)) | ||||
| 		reset_control_assert(drv_data->rstc); | ||||
| 	reset_control_assert(drv_data->rstc); | ||||
| exit_clk: | ||||
| 	/* Not all platforms have a clk */ | ||||
| 	if (!IS_ERR(drv_data->clk)) | ||||
| @ -968,8 +964,7 @@ mv64xxx_i2c_remove(struct platform_device *dev) | ||||
| 
 | ||||
| 	i2c_del_adapter(&drv_data->adapter); | ||||
| 	free_irq(drv_data->irq, drv_data); | ||||
| 	if (!IS_ERR_OR_NULL(drv_data->rstc)) | ||||
| 		reset_control_assert(drv_data->rstc); | ||||
| 	reset_control_assert(drv_data->rstc); | ||||
| 	/* Not all platforms have a clk */ | ||||
| 	if (!IS_ERR(drv_data->clk)) | ||||
| 		clk_disable_unprepare(drv_data->clk); | ||||
|  | ||||
| @ -700,6 +700,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, | ||||
| 
 | ||||
| 	pm_runtime_get_sync(dev); | ||||
| 
 | ||||
| 	rcar_i2c_init(priv); | ||||
| 
 | ||||
| 	ret = rcar_i2c_bus_barrier(priv); | ||||
| 	if (ret < 0) | ||||
| 		goto out; | ||||
| @ -751,6 +753,7 @@ static int rcar_reg_slave(struct i2c_client *slave) | ||||
| 	if (slave->flags & I2C_CLIENT_TEN) | ||||
| 		return -EAFNOSUPPORT; | ||||
| 
 | ||||
| 	/* Keep device active for slave address detection logic */ | ||||
| 	pm_runtime_get_sync(rcar_i2c_priv_to_dev(priv)); | ||||
| 
 | ||||
| 	priv->slave = slave; | ||||
| @ -854,15 +857,14 @@ static int rcar_i2c_probe(struct platform_device *pdev) | ||||
| 	priv->dma_direction = DMA_NONE; | ||||
| 	priv->dma_rx = priv->dma_tx = ERR_PTR(-EPROBE_DEFER); | ||||
| 
 | ||||
| 	/* Activate device for clock calculation */ | ||||
| 	pm_runtime_enable(dev); | ||||
| 	pm_runtime_get_sync(dev); | ||||
| 	ret = rcar_i2c_clock_calculate(priv, &i2c_t); | ||||
| 	if (ret < 0) | ||||
| 		goto out_pm_put; | ||||
| 
 | ||||
| 	rcar_i2c_init(priv); | ||||
| 
 | ||||
| 	/* Don't suspend when multi-master to keep arbitration working */ | ||||
| 	/* Stay always active when multi-master to keep arbitration working */ | ||||
| 	if (of_property_read_bool(dev->of_node, "multi-master")) | ||||
| 		priv->flags |= ID_P_PM_BLOCKED; | ||||
| 	else | ||||
|  | ||||
| @ -18,6 +18,9 @@ | ||||
| #define ACPI_SMBUS_HC_CLASS		"smbus" | ||||
| #define ACPI_SMBUS_HC_DEVICE_NAME	"cmi" | ||||
| 
 | ||||
| /* SMBUS HID definition as supported by Microsoft Windows */ | ||||
| #define ACPI_SMBUS_MS_HID		"SMB0001" | ||||
| 
 | ||||
| ACPI_MODULE_NAME("smbus_cmi"); | ||||
| 
 | ||||
| struct smbus_methods_t { | ||||
| @ -51,6 +54,7 @@ static const struct smbus_methods_t ibm_smbus_methods = { | ||||
| static const struct acpi_device_id acpi_smbus_cmi_ids[] = { | ||||
| 	{"SMBUS01", (kernel_ulong_t)&smbus_methods}, | ||||
| 	{ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods}, | ||||
| 	{ACPI_SMBUS_MS_HID, (kernel_ulong_t)&smbus_methods}, | ||||
| 	{"", 0} | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids); | ||||
|  | ||||
| @ -340,7 +340,7 @@ static struct platform_driver tegra_bpmp_i2c_driver = { | ||||
| }; | ||||
| module_platform_driver(tegra_bpmp_i2c_driver); | ||||
| 
 | ||||
| MODULE_DESCRIPTION("NVIDIA Tegra BPMP I2C bus contoller driver"); | ||||
| MODULE_DESCRIPTION("NVIDIA Tegra BPMP I2C bus controller driver"); | ||||
| MODULE_AUTHOR("Shardar Shariff Md <smohammed@nvidia.com>"); | ||||
| MODULE_AUTHOR("Juha-Matti Tilli"); | ||||
| MODULE_LICENSE("GPL v2"); | ||||
|  | ||||
| @ -85,16 +85,22 @@ static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	i2c->clk = clk_get(dev, NULL); | ||||
| 	if (IS_ERR(i2c->clk)) { | ||||
| 		i2c->clk = NULL; | ||||
| 		goto skip; | ||||
| 	} | ||||
| 	if (acpi_disabled) { | ||||
| 		/* DT */ | ||||
| 		i2c->clk = clk_get(dev, NULL); | ||||
| 		if (IS_ERR(i2c->clk)) { | ||||
| 			i2c->clk = NULL; | ||||
| 			goto skip; | ||||
| 		} | ||||
| 
 | ||||
| 	ret = clk_prepare_enable(i2c->clk); | ||||
| 	if (ret) | ||||
| 		goto skip; | ||||
| 	i2c->sys_freq = clk_get_rate(i2c->clk); | ||||
| 		ret = clk_prepare_enable(i2c->clk); | ||||
| 		if (ret) | ||||
| 			goto skip; | ||||
| 		i2c->sys_freq = clk_get_rate(i2c->clk); | ||||
| 	} else { | ||||
| 		/* ACPI */ | ||||
| 		device_property_read_u32(dev, "sclk", &i2c->sys_freq); | ||||
| 	} | ||||
| 
 | ||||
| skip: | ||||
| 	if (!i2c->sys_freq) | ||||
| @ -205,6 +211,7 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev, | ||||
| 
 | ||||
| 	i2c->adap = thunderx_i2c_ops; | ||||
| 	i2c->adap.retries = 5; | ||||
| 	i2c->adap.class = I2C_CLASS_HWMON; | ||||
| 	i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info; | ||||
| 	i2c->adap.dev.parent = dev; | ||||
| 	i2c->adap.dev.of_node = pdev->dev.of_node; | ||||
|  | ||||
| @ -432,6 +432,7 @@ MODULE_DEVICE_TABLE(of, xlp9xx_i2c_of_match); | ||||
| #ifdef CONFIG_ACPI | ||||
| static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = { | ||||
| 	{"BRCM9007", 0}, | ||||
| 	{"CAV9007",  0}, | ||||
| 	{} | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(acpi, xlp9xx_i2c_acpi_ids); | ||||
|  | ||||
| @ -112,6 +112,8 @@ struct i2c_acpi_lookup { | ||||
| 	acpi_handle adapter_handle; | ||||
| 	acpi_handle device_handle; | ||||
| 	acpi_handle search_handle; | ||||
| 	int n; | ||||
| 	int index; | ||||
| 	u32 speed; | ||||
| 	u32 min_speed; | ||||
| }; | ||||
| @ -130,6 +132,9 @@ static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data) | ||||
| 	if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	if (lookup->index != -1 && lookup->n++ != lookup->index) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	status = acpi_get_handle(lookup->device_handle, | ||||
| 				 sb->resource_source.string_ptr, | ||||
| 				 &lookup->adapter_handle); | ||||
| @ -182,6 +187,7 @@ static int i2c_acpi_get_info(struct acpi_device *adev, | ||||
| 
 | ||||
| 	memset(&lookup, 0, sizeof(lookup)); | ||||
| 	lookup.info = info; | ||||
| 	lookup.index = -1; | ||||
| 
 | ||||
| 	ret = i2c_acpi_do_lookup(adev, &lookup); | ||||
| 	if (ret) | ||||
| @ -328,6 +334,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev) | ||||
| 	lookup.search_handle = ACPI_HANDLE(dev); | ||||
| 	lookup.min_speed = UINT_MAX; | ||||
| 	lookup.info = &dummy; | ||||
| 	lookup.index = -1; | ||||
| 
 | ||||
| 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||||
| 				     I2C_ACPI_MAX_SCAN_DEPTH, | ||||
| @ -414,6 +421,55 @@ static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, | ||||
| static struct notifier_block i2c_acpi_notifier = { | ||||
| 	.notifier_call = i2c_acpi_notify, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * i2c_acpi_new_device - Create i2c-client for the Nth I2cSerialBus resource | ||||
|  * @dev:     Device owning the ACPI resources to get the client from | ||||
|  * @index:   Index of ACPI resource to get | ||||
|  * @info:    describes the I2C device; note this is modified (addr gets set) | ||||
|  * Context: can sleep | ||||
|  * | ||||
|  * By default the i2c subsys creates an i2c-client for the first I2cSerialBus | ||||
|  * resource of an acpi_device, but some acpi_devices have multiple I2cSerialBus | ||||
|  * resources, in that case this function can be used to create an i2c-client | ||||
|  * for other I2cSerialBus resources in the Current Resource Settings table. | ||||
|  * | ||||
|  * Also see i2c_new_device, which this function calls to create the i2c-client. | ||||
|  * | ||||
|  * Returns a pointer to the new i2c-client, or NULL if the adapter is not found. | ||||
|  */ | ||||
| struct i2c_client *i2c_acpi_new_device(struct device *dev, int index, | ||||
| 				       struct i2c_board_info *info) | ||||
| { | ||||
| 	struct i2c_acpi_lookup lookup; | ||||
| 	struct i2c_adapter *adapter; | ||||
| 	struct acpi_device *adev; | ||||
| 	LIST_HEAD(resource_list); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	adev = ACPI_COMPANION(dev); | ||||
| 	if (!adev) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	memset(&lookup, 0, sizeof(lookup)); | ||||
| 	lookup.info = info; | ||||
| 	lookup.device_handle = acpi_device_handle(adev); | ||||
| 	lookup.index = index; | ||||
| 
 | ||||
| 	ret = acpi_dev_get_resources(adev, &resource_list, | ||||
| 				     i2c_acpi_fill_info, &lookup); | ||||
| 	acpi_dev_free_resource_list(&resource_list); | ||||
| 
 | ||||
| 	if (ret < 0 || !info->addr) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle); | ||||
| 	if (!adapter) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	return i2c_new_device(adapter, info); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(i2c_acpi_new_device); | ||||
| #else /* CONFIG_ACPI */ | ||||
| static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { } | ||||
| extern struct notifier_block i2c_acpi_notifier; | ||||
| @ -929,7 +985,9 @@ static int i2c_device_probe(struct device *dev) | ||||
| 	if (!client) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (!client->irq) { | ||||
| 	driver = to_i2c_driver(dev->driver); | ||||
| 
 | ||||
| 	if (!client->irq && !driver->disable_i2c_core_irq_mapping) { | ||||
| 		int irq = -ENOENT; | ||||
| 
 | ||||
| 		if (client->flags & I2C_CLIENT_HOST_NOTIFY) { | ||||
| @ -951,8 +1009,6 @@ static int i2c_device_probe(struct device *dev) | ||||
| 		client->irq = irq; | ||||
| 	} | ||||
| 
 | ||||
| 	driver = to_i2c_driver(dev->driver); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * An I2C ID table is not mandatory, if and only if, a suitable Device | ||||
| 	 * Tree match table entry is supplied for the probing device. | ||||
|  | ||||
| @ -395,13 +395,16 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, | ||||
| 	if (force_nr) { | ||||
| 		priv->adap.nr = force_nr; | ||||
| 		ret = i2c_add_numbered_adapter(&priv->adap); | ||||
| 		dev_err(&parent->dev, | ||||
| 			"failed to add mux-adapter %u as bus %u (error=%d)\n", | ||||
| 			chan_id, force_nr, ret); | ||||
| 	} else { | ||||
| 		ret = i2c_add_adapter(&priv->adap); | ||||
| 		dev_err(&parent->dev, | ||||
| 			"failed to add mux-adapter %u (error=%d)\n", | ||||
| 			chan_id, ret); | ||||
| 	} | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(&parent->dev, | ||||
| 			"failed to add mux-adapter (error=%d)\n", | ||||
| 			ret); | ||||
| 		kfree(priv); | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| @ -30,6 +30,17 @@ config I2C_MUX_GPIO | ||||
| 	  This driver can also be built as a module.  If so, the module | ||||
| 	  will be called i2c-mux-gpio. | ||||
| 
 | ||||
| config I2C_MUX_LTC4306 | ||||
| 	tristate "LTC LTC4306/5 I2C multiplexer" | ||||
| 	select GPIOLIB | ||||
| 	select REGMAP_I2C | ||||
| 	help | ||||
| 	  If you say yes here you get support for the Analog Devices | ||||
| 	  LTC4306 or LTC4305 I2C mux/switch devices. | ||||
| 
 | ||||
| 	  This driver can also be built as a module.  If so, the module | ||||
| 	  will be called i2c-mux-ltc4306. | ||||
| 
 | ||||
| config I2C_MUX_PCA9541 | ||||
| 	tristate "NXP PCA9541 I2C Master Selector" | ||||
| 	help | ||||
|  | ||||
| @ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE)	+= i2c-arb-gpio-challenge.o | ||||
| obj-$(CONFIG_I2C_DEMUX_PINCTRL)		+= i2c-demux-pinctrl.o | ||||
| 
 | ||||
| obj-$(CONFIG_I2C_MUX_GPIO)	+= i2c-mux-gpio.o | ||||
| obj-$(CONFIG_I2C_MUX_LTC4306)	+= i2c-mux-ltc4306.o | ||||
| obj-$(CONFIG_I2C_MUX_MLXCPLD)	+= i2c-mux-mlxcpld.o | ||||
| obj-$(CONFIG_I2C_MUX_PCA9541)	+= i2c-mux-pca9541.o | ||||
| obj-$(CONFIG_I2C_MUX_PCA954x)	+= i2c-mux-pca954x.o | ||||
|  | ||||
| @ -202,10 +202,8 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) | ||||
| 
 | ||||
| 	/* Actually add the mux adapter */ | ||||
| 	ret = i2c_mux_add_adapter(muxc, 0, 0, 0); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Failed to add adapter\n"); | ||||
| 	if (ret) | ||||
| 		i2c_put_adapter(muxc->parent); | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| @ -245,10 +245,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) | ||||
| 		unsigned int class = mux->data.classes ? mux->data.classes[i] : 0; | ||||
| 
 | ||||
| 		ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class); | ||||
| 		if (ret) { | ||||
| 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i); | ||||
| 		if (ret) | ||||
| 			goto add_adapter_failed; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	dev_info(&pdev->dev, "%d port mux on %s adapter\n", | ||||
|  | ||||
							
								
								
									
										322
									
								
								drivers/i2c/muxes/i2c-mux-ltc4306.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								drivers/i2c/muxes/i2c-mux-ltc4306.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,322 @@ | ||||
| /*
 | ||||
|  * Linear Technology LTC4306 and LTC4305 I2C multiplexer/switch | ||||
|  * | ||||
|  * Copyright (C) 2017 Analog Devices Inc. | ||||
|  * | ||||
|  * Licensed under the GPL-2. | ||||
|  * | ||||
|  * Based on: i2c-mux-pca954x.c | ||||
|  * | ||||
|  * Datasheet: http://cds.linear.com/docs/en/datasheet/4306.pdf
 | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/gpio/consumer.h> | ||||
| #include <linux/gpio/driver.h> | ||||
| #include <linux/i2c-mux.h> | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/property.h> | ||||
| #include <linux/regmap.h> | ||||
| #include <linux/slab.h> | ||||
| 
 | ||||
| #define LTC4305_MAX_NCHANS 2 | ||||
| #define LTC4306_MAX_NCHANS 4 | ||||
| 
 | ||||
| #define LTC_REG_STATUS	0x0 | ||||
| #define LTC_REG_CONFIG	0x1 | ||||
| #define LTC_REG_MODE	0x2 | ||||
| #define LTC_REG_SWITCH	0x3 | ||||
| 
 | ||||
| #define LTC_DOWNSTREAM_ACCL_EN	BIT(6) | ||||
| #define LTC_UPSTREAM_ACCL_EN	BIT(7) | ||||
| 
 | ||||
| #define LTC_GPIO_ALL_INPUT	0xC0 | ||||
| #define LTC_SWITCH_MASK		0xF0 | ||||
| 
 | ||||
| enum ltc_type { | ||||
| 	ltc_4305, | ||||
| 	ltc_4306, | ||||
| }; | ||||
| 
 | ||||
| struct chip_desc { | ||||
| 	u8 nchans; | ||||
| 	u8 num_gpios; | ||||
| }; | ||||
| 
 | ||||
| struct ltc4306 { | ||||
| 	struct regmap *regmap; | ||||
| 	struct gpio_chip gpiochip; | ||||
| 	const struct chip_desc *chip; | ||||
| }; | ||||
| 
 | ||||
| static const struct chip_desc chips[] = { | ||||
| 	[ltc_4305] = { | ||||
| 		.nchans = LTC4305_MAX_NCHANS, | ||||
| 	}, | ||||
| 	[ltc_4306] = { | ||||
| 		.nchans = LTC4306_MAX_NCHANS, | ||||
| 		.num_gpios = 2, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static bool ltc4306_is_volatile_reg(struct device *dev, unsigned int reg) | ||||
| { | ||||
| 	return (reg == LTC_REG_CONFIG) ? true : false; | ||||
| } | ||||
| 
 | ||||
| static const struct regmap_config ltc4306_regmap_config = { | ||||
| 	.reg_bits = 8, | ||||
| 	.val_bits = 8, | ||||
| 	.max_register = LTC_REG_SWITCH, | ||||
| 	.volatile_reg = ltc4306_is_volatile_reg, | ||||
| 	.cache_type = REGCACHE_FLAT, | ||||
| }; | ||||
| 
 | ||||
| static int ltc4306_gpio_get(struct gpio_chip *chip, unsigned int offset) | ||||
| { | ||||
| 	struct ltc4306 *data = gpiochip_get_data(chip); | ||||
| 	unsigned int val; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = regmap_read(data->regmap, LTC_REG_CONFIG, &val); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	return !!(val & BIT(1 - offset)); | ||||
| } | ||||
| 
 | ||||
| static void ltc4306_gpio_set(struct gpio_chip *chip, unsigned int offset, | ||||
| 			     int value) | ||||
| { | ||||
| 	struct ltc4306 *data = gpiochip_get_data(chip); | ||||
| 
 | ||||
| 	regmap_update_bits(data->regmap, LTC_REG_CONFIG, BIT(5 - offset), | ||||
| 			   value ? BIT(5 - offset) : 0); | ||||
| } | ||||
| 
 | ||||
| static int ltc4306_gpio_get_direction(struct gpio_chip *chip, | ||||
| 				      unsigned int offset) | ||||
| { | ||||
| 	struct ltc4306 *data = gpiochip_get_data(chip); | ||||
| 	unsigned int val; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = regmap_read(data->regmap, LTC_REG_MODE, &val); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	return !!(val & BIT(7 - offset)); | ||||
| } | ||||
| 
 | ||||
| static int ltc4306_gpio_direction_input(struct gpio_chip *chip, | ||||
| 					unsigned int offset) | ||||
| { | ||||
| 	struct ltc4306 *data = gpiochip_get_data(chip); | ||||
| 
 | ||||
| 	return regmap_update_bits(data->regmap, LTC_REG_MODE, | ||||
| 				  BIT(7 - offset), BIT(7 - offset)); | ||||
| } | ||||
| 
 | ||||
| static int ltc4306_gpio_direction_output(struct gpio_chip *chip, | ||||
| 					 unsigned int offset, int value) | ||||
| { | ||||
| 	struct ltc4306 *data = gpiochip_get_data(chip); | ||||
| 
 | ||||
| 	ltc4306_gpio_set(chip, offset, value); | ||||
| 	return regmap_update_bits(data->regmap, LTC_REG_MODE, | ||||
| 				  BIT(7 - offset), 0); | ||||
| } | ||||
| 
 | ||||
| static int ltc4306_gpio_set_config(struct gpio_chip *chip, | ||||
| 				   unsigned int offset, unsigned long config) | ||||
| { | ||||
| 	struct ltc4306 *data = gpiochip_get_data(chip); | ||||
| 	unsigned int val; | ||||
| 
 | ||||
| 	switch (pinconf_to_config_param(config)) { | ||||
| 	case PIN_CONFIG_DRIVE_OPEN_DRAIN: | ||||
| 		val = 0; | ||||
| 		break; | ||||
| 	case PIN_CONFIG_DRIVE_PUSH_PULL: | ||||
| 		val = BIT(4 - offset); | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -ENOTSUPP; | ||||
| 	} | ||||
| 
 | ||||
| 	return regmap_update_bits(data->regmap, LTC_REG_MODE, | ||||
| 				  BIT(4 - offset), val); | ||||
| } | ||||
| 
 | ||||
| static int ltc4306_gpio_init(struct ltc4306 *data) | ||||
| { | ||||
| 	struct device *dev = regmap_get_device(data->regmap); | ||||
| 
 | ||||
| 	if (!data->chip->num_gpios) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	data->gpiochip.label = dev_name(dev); | ||||
| 	data->gpiochip.base = -1; | ||||
| 	data->gpiochip.ngpio = data->chip->num_gpios; | ||||
| 	data->gpiochip.parent = dev; | ||||
| 	data->gpiochip.can_sleep = true; | ||||
| 	data->gpiochip.get_direction = ltc4306_gpio_get_direction; | ||||
| 	data->gpiochip.direction_input = ltc4306_gpio_direction_input; | ||||
| 	data->gpiochip.direction_output = ltc4306_gpio_direction_output; | ||||
| 	data->gpiochip.get = ltc4306_gpio_get; | ||||
| 	data->gpiochip.set = ltc4306_gpio_set; | ||||
| 	data->gpiochip.set_config = ltc4306_gpio_set_config; | ||||
| 	data->gpiochip.owner = THIS_MODULE; | ||||
| 
 | ||||
| 	/* gpiolib assumes all GPIOs default input */ | ||||
| 	regmap_write(data->regmap, LTC_REG_MODE, LTC_GPIO_ALL_INPUT); | ||||
| 
 | ||||
| 	return devm_gpiochip_add_data(dev, &data->gpiochip, data); | ||||
| } | ||||
| 
 | ||||
| static int ltc4306_select_mux(struct i2c_mux_core *muxc, u32 chan) | ||||
| { | ||||
| 	struct ltc4306 *data = i2c_mux_priv(muxc); | ||||
| 
 | ||||
| 	return regmap_update_bits(data->regmap, LTC_REG_SWITCH, | ||||
| 				  LTC_SWITCH_MASK, BIT(7 - chan)); | ||||
| } | ||||
| 
 | ||||
| static int ltc4306_deselect_mux(struct i2c_mux_core *muxc, u32 chan) | ||||
| { | ||||
| 	struct ltc4306 *data = i2c_mux_priv(muxc); | ||||
| 
 | ||||
| 	return regmap_update_bits(data->regmap, LTC_REG_SWITCH, | ||||
| 				  LTC_SWITCH_MASK, 0); | ||||
| } | ||||
| 
 | ||||
| static const struct i2c_device_id ltc4306_id[] = { | ||||
| 	{ "ltc4305", ltc_4305 }, | ||||
| 	{ "ltc4306", ltc_4306 }, | ||||
| 	{ } | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(i2c, ltc4306_id); | ||||
| 
 | ||||
| static const struct of_device_id ltc4306_of_match[] = { | ||||
| 	{ .compatible = "lltc,ltc4305", .data = &chips[ltc_4305] }, | ||||
| 	{ .compatible = "lltc,ltc4306", .data = &chips[ltc_4306] }, | ||||
| 	{ } | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, ltc4306_of_match); | ||||
| 
 | ||||
| static int ltc4306_probe(struct i2c_client *client, | ||||
| 			 const struct i2c_device_id *id) | ||||
| { | ||||
| 	struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); | ||||
| 	const struct chip_desc *chip; | ||||
| 	struct i2c_mux_core *muxc; | ||||
| 	struct ltc4306 *data; | ||||
| 	struct gpio_desc *gpio; | ||||
| 	bool idle_disc; | ||||
| 	unsigned int val = 0; | ||||
| 	int num, ret; | ||||
| 
 | ||||
| 	chip = of_device_get_match_data(&client->dev); | ||||
| 
 | ||||
| 	if (!chip) | ||||
| 		chip = &chips[id->driver_data]; | ||||
| 
 | ||||
| 	idle_disc = device_property_read_bool(&client->dev, | ||||
| 					      "i2c-mux-idle-disconnect"); | ||||
| 
 | ||||
| 	muxc = i2c_mux_alloc(adap, &client->dev, | ||||
| 			     chip->nchans, sizeof(*data), | ||||
| 			     I2C_MUX_LOCKED, ltc4306_select_mux, | ||||
| 			     idle_disc ? ltc4306_deselect_mux : NULL); | ||||
| 	if (!muxc) | ||||
| 		return -ENOMEM; | ||||
| 	data = i2c_mux_priv(muxc); | ||||
| 	data->chip = chip; | ||||
| 
 | ||||
| 	i2c_set_clientdata(client, muxc); | ||||
| 
 | ||||
| 	data->regmap = devm_regmap_init_i2c(client, <c4306_regmap_config); | ||||
| 	if (IS_ERR(data->regmap)) { | ||||
| 		ret = PTR_ERR(data->regmap); | ||||
| 		dev_err(&client->dev, "Failed to allocate register map: %d\n", | ||||
| 			ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Reset and enable the mux if an enable GPIO is specified. */ | ||||
| 	gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW); | ||||
| 	if (IS_ERR(gpio)) | ||||
| 		return PTR_ERR(gpio); | ||||
| 
 | ||||
| 	if (gpio) { | ||||
| 		udelay(1); | ||||
| 		gpiod_set_value(gpio, 1); | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Write the mux register at addr to verify | ||||
| 	 * that the mux is in fact present. This also | ||||
| 	 * initializes the mux to disconnected state. | ||||
| 	 */ | ||||
| 	if (regmap_write(data->regmap, LTC_REG_SWITCH, 0) < 0) { | ||||
| 		dev_warn(&client->dev, "probe failed\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	if (device_property_read_bool(&client->dev, | ||||
| 				      "ltc,downstream-accelerators-enable")) | ||||
| 		val |= LTC_DOWNSTREAM_ACCL_EN; | ||||
| 
 | ||||
| 	if (device_property_read_bool(&client->dev, | ||||
| 				      "ltc,upstream-accelerators-enable")) | ||||
| 		val |= LTC_UPSTREAM_ACCL_EN; | ||||
| 
 | ||||
| 	if (regmap_write(data->regmap, LTC_REG_CONFIG, val) < 0) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	ret = ltc4306_gpio_init(data); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	/* Now create an adapter for each channel */ | ||||
| 	for (num = 0; num < chip->nchans; num++) { | ||||
| 		ret = i2c_mux_add_adapter(muxc, 0, num, 0); | ||||
| 		if (ret) { | ||||
| 			i2c_mux_del_adapters(muxc); | ||||
| 			return ret; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	dev_info(&client->dev, | ||||
| 		 "registered %d multiplexed busses for I2C switch %s\n", | ||||
| 		 num, client->name); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ltc4306_remove(struct i2c_client *client) | ||||
| { | ||||
| 	struct i2c_mux_core *muxc = i2c_get_clientdata(client); | ||||
| 
 | ||||
| 	i2c_mux_del_adapters(muxc); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static struct i2c_driver ltc4306_driver = { | ||||
| 	.driver		= { | ||||
| 		.name	= "ltc4306", | ||||
| 		.of_match_table = of_match_ptr(ltc4306_of_match), | ||||
| 	}, | ||||
| 	.probe		= ltc4306_probe, | ||||
| 	.remove		= ltc4306_remove, | ||||
| 	.id_table	= ltc4306_id, | ||||
| }; | ||||
| 
 | ||||
| module_i2c_driver(ltc4306_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); | ||||
| MODULE_DESCRIPTION("Linear Technology LTC4306, LTC4305 I2C mux/switch driver"); | ||||
| MODULE_LICENSE("GPL v2"); | ||||
| @ -369,10 +369,8 @@ static int pca9541_probe(struct i2c_client *client, | ||||
| 	i2c_set_clientdata(client, muxc); | ||||
| 
 | ||||
| 	ret = i2c_mux_add_adapter(muxc, force, 0, 0); | ||||
| 	if (ret) { | ||||
| 		dev_err(&client->dev, "failed to register master selector\n"); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	dev_info(&client->dev, "registered master selector for I2C %s\n", | ||||
| 		 client->name); | ||||
|  | ||||
| @ -84,7 +84,7 @@ struct pca954x { | ||||
| 
 | ||||
| 	struct irq_domain *irq; | ||||
| 	unsigned int irq_mask; | ||||
| 	spinlock_t lock; | ||||
| 	raw_spinlock_t lock; | ||||
| }; | ||||
| 
 | ||||
| /* Provide specs for the PCA954x types we know about */ | ||||
| @ -252,13 +252,13 @@ static void pca954x_irq_mask(struct irq_data *idata) | ||||
| 	unsigned int pos = idata->hwirq; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&data->lock, flags); | ||||
| 	raw_spin_lock_irqsave(&data->lock, flags); | ||||
| 
 | ||||
| 	data->irq_mask &= ~BIT(pos); | ||||
| 	if (!data->irq_mask) | ||||
| 		disable_irq(data->client->irq); | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&data->lock, flags); | ||||
| 	raw_spin_unlock_irqrestore(&data->lock, flags); | ||||
| } | ||||
| 
 | ||||
| static void pca954x_irq_unmask(struct irq_data *idata) | ||||
| @ -267,13 +267,13 @@ static void pca954x_irq_unmask(struct irq_data *idata) | ||||
| 	unsigned int pos = idata->hwirq; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&data->lock, flags); | ||||
| 	raw_spin_lock_irqsave(&data->lock, flags); | ||||
| 
 | ||||
| 	if (!data->irq_mask) | ||||
| 		enable_irq(data->client->irq); | ||||
| 	data->irq_mask |= BIT(pos); | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&data->lock, flags); | ||||
| 	raw_spin_unlock_irqrestore(&data->lock, flags); | ||||
| } | ||||
| 
 | ||||
| static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) | ||||
| @ -299,7 +299,7 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc) | ||||
| 	if (!data->chip->has_irq || client->irq <= 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	spin_lock_init(&data->lock); | ||||
| 	raw_spin_lock_init(&data->lock); | ||||
| 
 | ||||
| 	data->irq = irq_domain_add_linear(client->dev.of_node, | ||||
| 					  data->chip->nchans, | ||||
| @ -413,13 +413,8 @@ static int pca954x_probe(struct i2c_client *client, | ||||
| 				   idle_disconnect_dt) << num; | ||||
| 
 | ||||
| 		ret = i2c_mux_add_adapter(muxc, force, num, class); | ||||
| 
 | ||||
| 		if (ret) { | ||||
| 			dev_err(&client->dev, | ||||
| 				"failed to register multiplexed adapter" | ||||
| 				" %d as bus %d\n", num, force); | ||||
| 		if (ret) | ||||
| 			goto fail_del_adapters; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	dev_info(&client->dev, | ||||
|  | ||||
| @ -245,10 +245,8 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev) | ||||
| 				(mux->pdata->base_bus_num + i) : 0; | ||||
| 
 | ||||
| 		ret = i2c_mux_add_adapter(muxc, bus, i, 0); | ||||
| 		if (ret) { | ||||
| 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i); | ||||
| 		if (ret) | ||||
| 			goto err_del_adapter; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
|  | ||||
| @ -222,10 +222,8 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) | ||||
| 		class = mux->data.classes ? mux->data.classes[i] : 0; | ||||
| 
 | ||||
| 		ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class); | ||||
| 		if (ret) { | ||||
| 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i); | ||||
| 		if (ret) | ||||
| 			goto add_adapter_failed; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	dev_dbg(&pdev->dev, "%d port mux on %s adapter\n", | ||||
|  | ||||
| @ -576,17 +576,10 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev) | ||||
| 
 | ||||
| int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no) | ||||
| { | ||||
| 	int rc; | ||||
| 
 | ||||
| 	rc = i2c_mux_add_adapter(dev->muxc, | ||||
| 				 0, | ||||
| 				 mux_no /* chan_id */, | ||||
| 				 0 /* class */); | ||||
| 	if (rc) | ||||
| 		dev_warn(dev->dev, | ||||
| 			 "i2c mux %d register FAILED\n", mux_no); | ||||
| 
 | ||||
| 	return rc; | ||||
| 	return i2c_mux_add_adapter(dev->muxc, | ||||
| 				   0, | ||||
| 				   mux_no /* chan_id */, | ||||
| 				   0 /* class */); | ||||
| } | ||||
| 
 | ||||
| void cx231xx_i2c_mux_unregister(struct cx231xx *dev) | ||||
|  | ||||
| @ -149,6 +149,7 @@ enum i2c_alert_protocol { | ||||
|  * @detect: Callback for device detection | ||||
|  * @address_list: The I2C addresses to probe (for detect) | ||||
|  * @clients: List of detected clients we created (for i2c-core use only) | ||||
|  * @disable_i2c_core_irq_mapping: Tell the i2c-core to not do irq-mapping | ||||
|  * | ||||
|  * The driver.owner field should be set to the module owner of this driver. | ||||
|  * The driver.name field should be set to the name of this driver. | ||||
| @ -212,6 +213,8 @@ struct i2c_driver { | ||||
| 	int (*detect)(struct i2c_client *, struct i2c_board_info *); | ||||
| 	const unsigned short *address_list; | ||||
| 	struct list_head clients; | ||||
| 
 | ||||
| 	bool disable_i2c_core_irq_mapping; | ||||
| }; | ||||
| #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver) | ||||
| 
 | ||||
| @ -824,11 +827,18 @@ static inline const struct of_device_id | ||||
| 
 | ||||
| #if IS_ENABLED(CONFIG_ACPI) | ||||
| u32 i2c_acpi_find_bus_speed(struct device *dev); | ||||
| struct i2c_client *i2c_acpi_new_device(struct device *dev, int index, | ||||
| 				       struct i2c_board_info *info); | ||||
| #else | ||||
| static inline u32 i2c_acpi_find_bus_speed(struct device *dev) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| static inline struct i2c_client *i2c_acpi_new_device(struct device *dev, | ||||
| 					int index, struct i2c_board_info *info) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| #endif /* CONFIG_ACPI */ | ||||
| 
 | ||||
| #endif /* _LINUX_I2C_H */ | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user