Skip to content
Browse files

Add kernel parameter to enable i2c-6 pinctrl mapping

By default the pinctrl platform driver for Merrifield will register a
pinctrl mapping for i2c-6 that sets the correct pinmux once i2c-6 is
probed. If this is not desired, the following can be added to the kernel
command line: platform_mrfld_pinctrl.pinctrl_i2c6=n

Since the SCU driver is probed after the I2C bus drivers (due to the
order of PCI IDs), setting the pinmux for i2c-6 will fail since the SCU
driver must be probed to successfully set the bufcfg. As a workaround,
the I2C bus driver (i2c-designware-pci) can be compiled as a LKM and
inserted after all other PCI devices have been probed.
  • Loading branch information
svenschwermer committed Oct 13, 2017
1 parent 54f9552 commit 19dc84267614bc94eb953b7c59a12dae59d995e1
@@ -14,12 +14,16 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/machine.h>
#include <linux/moduleparam.h>

#include <asm/intel-mid.h>

#define FLIS_BASE_ADDR 0xff0c0000
#define FLIS_LENGTH 0x8000

static bool pinctrl_i2c6 = true;

static struct resource mrfld_pinctrl_mmio_resource = {
.start = FLIS_BASE_ADDR,
@@ -33,11 +37,37 @@ static struct platform_device mrfld_pinctrl_device = {
.num_resources = 1,

static const struct pinctrl_map mapping[] __initconst = {
.dev_name = "0000:00:09.1",
.ctrl_dev_name = "pinctrl-merrifield", = "i2c6_grp",
.data.mux.function = "i2c6",

static int __init mrfld_pinctrl_init(void)
if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER)
return platform_device_register(&mrfld_pinctrl_device);
int ret;

if (intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_TANGIER)
return -ENODEV;

return -ENODEV;
ret = platform_device_register(&mrfld_pinctrl_device);
if (ret)
return ret;

if (pinctrl_i2c6) {
ret = pinctrl_register_mappings(mapping, ARRAY_SIZE(mapping));
if (ret)
pr_err("Failed to register i2c6 pinctrl mapping\n");

return 0;

module_param(pinctrl_i2c6, bool, 0444);
MODULE_PARM_DESC(pinctrl_i2c6, "Configure pinctrl to use i2c-6");
@@ -564,14 +564,18 @@ static int mrfld_update_phys(struct mrfld_pinctrl *mp, unsigned int pin,
void __iomem *bufcfg;
phys_addr_t phys;
u32 v, value;
int ret;

bufcfg = mrfld_get_bufcfg(mp, pin);
value = readl(bufcfg);

v = (value & ~mask) | (bits & mask);

phys = mrfld_get_phys(mp, pin);
return intel_scu_ipc_raw_command(cmd, 0, (u8 *)&v, 4, NULL, 0, phys, 0);
ret = intel_scu_ipc_raw_command(cmd, 0, (u8 *)&v, 4, NULL, 0, phys, 0);
if (ret)
dev_err(mp->dev, "Failed to set bufcfg via SCU IPC for pin %u (%d)\n", pin, ret);
return ret;

static int mrfld_get_groups_count(struct pinctrl_dev *pctldev)
@@ -682,6 +686,7 @@ static int mrfld_pinmux_set_mux(struct pinctrl_dev *pctldev,

if (protected) {
for (i = 0; i < grp->npins; i++)
/* TODO: We always return success, because rolling back is a challenge */
mrfld_update_phys(mp, grp->pins[i], bits, mask);
return 0;

4 comments on commit 19dc842


This comment has been minimized.

Copy link

@andy-shev andy-shev replied Oct 15, 2017

Thanks for finding a root cause why it wasn't working!
Though, looking to above change makes me clear that it should be done rather in U-Boot.


This comment has been minimized.

Copy link

@andy-shev andy-shev replied Oct 15, 2017

Btw, there are macros to help filling mappings structure


This comment has been minimized.

Copy link
Owner Author

@svenschwermer svenschwermer replied Oct 15, 2017

I won't deny that this is a hack ;)
I am aware of the macros, but I had to go back and forth a lot and not using the macro gave me some extra agility. For some reason, I never went back to using the macro.


This comment has been minimized.

Copy link

@andy-shev andy-shev replied Apr 5, 2020

TWIMC, I2C mode has been "fixed" thru U-Boot: u-boot/u-boot@f26b260

Please sign in to comment.
You can’t perform that action at this time.