android_kernel_modules_leno.../drivers/pinctrl/pinctrl-intel-mid.c

545 lines
15 KiB
C

/*
* pinctrl-intel-mid.c Driver for the Intel MID pin controller
*
* Copyright (c) 2013, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <asm/intel_scu_flis.h>
#include <asm/intel_mid_pinctrl.h>
/* Pin names for the pinctrl subsystem */
static const struct pinctrl_pin_desc ctp_pins[] = {
PINCTRL_PIN(0, "i2s_2_clk"),
PINCTRL_PIN(1, "i2s_2_fs"),
PINCTRL_PIN(2, "i2s_2_rxd"),
PINCTRL_PIN(3, "i2s_2_txd"),
PINCTRL_PIN(4, "msic_reset_b"),
PINCTRL_PIN(5, "spi_0_clk"),
PINCTRL_PIN(6, "spi_0_sdi"),
PINCTRL_PIN(7, "spi_0_sdo"),
PINCTRL_PIN(8, "spi_0_ss"),
PINCTRL_PIN(9, "svid_clkout"),
PINCTRL_PIN(10, "svid_clksynch"),
PINCTRL_PIN(11, "svid_din"),
PINCTRL_PIN(12, "svid_dout"),
PINCTRL_PIN(13, "usb_ulpi_clk"),
PINCTRL_PIN(14, "usb_ulpi_data0"),
PINCTRL_PIN(15, "usb_ulpi_data1"),
PINCTRL_PIN(16, "usb_ulpi_data2"),
PINCTRL_PIN(17, "usb_ulpi_data3"),
PINCTRL_PIN(18, "usb_ulpi_data4"),
PINCTRL_PIN(19, "usb_ulpi_data5"),
PINCTRL_PIN(20, "usb_ulpi_data6"),
PINCTRL_PIN(21, "usb_ulpi_data7"),
PINCTRL_PIN(22, "usb_ulpi_dir"),
PINCTRL_PIN(23, "usb_ulpi_nxt"),
PINCTRL_PIN(24, "usb_ulpi_refclk"),
PINCTRL_PIN(25, "usb_ulpi_stp"),
PINCTRL_PIN(26, "ulpi1lpc_gpe_b"),
PINCTRL_PIN(27, "ulpi1lpc_lpc_ad0"),
PINCTRL_PIN(28, "ulpi1lpc_lpc_ad1"),
PINCTRL_PIN(29, "ulpi1lpc_lpc_ad2"),
PINCTRL_PIN(30, "ulpi1lpc_lpc_ad3"),
PINCTRL_PIN(31, "ulpi1lpc_lpc_clkout"),
PINCTRL_PIN(32, "ulpi1lpc_lpc_clkrun"),
PINCTRL_PIN(33, "ulpi1lpc_lpc_frame_b"),
PINCTRL_PIN(34, "ulpi1lpc_lpc_reset_b"),
PINCTRL_PIN(35, "ulpi1lpc_lpc_serirq"),
PINCTRL_PIN(36, "ulpi1lpc_lpc_smi_b"),
PINCTRL_PIN(37, "ulpi1lpc_usb_ulpi_1_clk"),
PINCTRL_PIN(38, "ulpi1lpc_usb_ulpi_1_data0"),
PINCTRL_PIN(39, "ulpi1lpc_usb_ulpi_1_data1"),
PINCTRL_PIN(40, "ulpi1lpc_usb_ulpi_1_data2"),
PINCTRL_PIN(41, "ulpi1lpc_usb_ulpi_1_data3"),
PINCTRL_PIN(42, "ulpi1lpc_usb_ulpi_1_data4"),
PINCTRL_PIN(43, "ulpi1lpc_usb_ulpi_1_data5"),
PINCTRL_PIN(44, "ulpi1lpc_usb_ulpi_1_data6"),
PINCTRL_PIN(45, "ulpi1lpc_usb_ulpi_1_data7"),
PINCTRL_PIN(46, "ulpi1lpc_usb_ulpi_1_dir"),
PINCTRL_PIN(47, "ulpi1lpc_usb_ulpi_1_nxt"),
PINCTRL_PIN(48, "ulpi1lpc_usb_ulpi_1_refclk"),
PINCTRL_PIN(49, "ulpi1lpc_usb_ulpi_1_stp"),
PINCTRL_PIN(50, "kbd_dkin0"),
PINCTRL_PIN(51, "kbd_dkin1"),
PINCTRL_PIN(52, "kbd_dkin2"),
PINCTRL_PIN(53, "kbd_dkin3"),
PINCTRL_PIN(54, "kbd_mkin0"),
PINCTRL_PIN(55, "kbd_mkin1"),
PINCTRL_PIN(56, "kbd_mkin2"),
PINCTRL_PIN(57, "kbd_mkin3"),
PINCTRL_PIN(58, "kbd_mkin4"),
PINCTRL_PIN(59, "kbd_mkin5"),
PINCTRL_PIN(60, "kbd_mkin6"),
PINCTRL_PIN(61, "kbd_mkin7"),
PINCTRL_PIN(62, "kbd_mkout0"),
PINCTRL_PIN(63, "kbd_mkout1"),
PINCTRL_PIN(64, "kbd_mkout2"),
PINCTRL_PIN(65, "kbd_mkout3"),
PINCTRL_PIN(66, "kbd_mkout4"),
PINCTRL_PIN(67, "kbd_mkout5"),
PINCTRL_PIN(68, "kbd_mkout6"),
PINCTRL_PIN(69, "kbd_mkout7"),
PINCTRL_PIN(70, "camerasb10"),
PINCTRL_PIN(71, "camerasb4"),
PINCTRL_PIN(72, "camerasb5"),
PINCTRL_PIN(73, "camerasb6"),
PINCTRL_PIN(74, "camerasb7"),
PINCTRL_PIN(75, "camerasb8"),
PINCTRL_PIN(76, "camerasb9"),
PINCTRL_PIN(77, "i2c_4_scl"),
PINCTRL_PIN(78, "i2c_4_sda"),
PINCTRL_PIN(79, "i2c_5_scl"),
PINCTRL_PIN(80, "i2c_5_sda"),
PINCTRL_PIN(81, "intd_dsi_te1"),
PINCTRL_PIN(82, "intd_dsi_te2"),
PINCTRL_PIN(83, "stio_0_cd_b"),
PINCTRL_PIN(84, "stio_0_clk"),
PINCTRL_PIN(85, "stio_0_cmd"),
PINCTRL_PIN(86, "stio_0_dat0"),
PINCTRL_PIN(87, "stio_0_dat1"),
PINCTRL_PIN(88, "stio_0_dat2"),
PINCTRL_PIN(89, "stio_0_dat3"),
PINCTRL_PIN(90, "stio_0_dat4"),
PINCTRL_PIN(91, "stio_0_dat5"),
PINCTRL_PIN(92, "stio_0_dat6"),
PINCTRL_PIN(93, "stio_0_dat7"),
PINCTRL_PIN(94, "stio_0_wp_b"),
PINCTRL_PIN(95, "camerasb0"),
PINCTRL_PIN(96, "camerasb1"),
PINCTRL_PIN(97, "camerasb2"),
PINCTRL_PIN(98, "camerasb3"),
PINCTRL_PIN(99, "ded_gpio10"),
PINCTRL_PIN(100, "ded_gpio11"),
PINCTRL_PIN(101, "ded_gpio12"),
PINCTRL_PIN(102, "ded_gpio13"),
PINCTRL_PIN(103, "ded_gpio14"),
PINCTRL_PIN(104, "ded_gpio15"),
PINCTRL_PIN(105, "ded_gpio16"),
PINCTRL_PIN(106, "ded_gpio17"),
PINCTRL_PIN(107, "ded_gpio18"),
PINCTRL_PIN(108, "ded_gpio19"),
PINCTRL_PIN(109, "ded_gpio20"),
PINCTRL_PIN(110, "ded_gpio21"),
PINCTRL_PIN(111, "ded_gpio22"),
PINCTRL_PIN(112, "ded_gpio23"),
PINCTRL_PIN(113, "ded_gpio24"),
PINCTRL_PIN(114, "ded_gpio25"),
PINCTRL_PIN(115, "ded_gpio26"),
PINCTRL_PIN(116, "ded_gpio27"),
PINCTRL_PIN(117, "ded_gpio28"),
PINCTRL_PIN(118, "ded_gpio29"),
PINCTRL_PIN(119, "ded_gpio30"),
PINCTRL_PIN(120, "ded_gpio8"),
PINCTRL_PIN(121, "ded_gpio9"),
PINCTRL_PIN(122, "mpti_nidnt_clk"),
PINCTRL_PIN(123, "mpti_nidnt_data0"),
PINCTRL_PIN(124, "mpti_nidnt_data1"),
PINCTRL_PIN(125, "mpti_nidnt_data2"),
PINCTRL_PIN(126, "mpti_nidnt_data3"),
PINCTRL_PIN(127, "stio_1_clk"),
PINCTRL_PIN(128, "stio_1_cmd"),
PINCTRL_PIN(129, "stio_1_dat0"),
PINCTRL_PIN(130, "stio_1_dat1"),
PINCTRL_PIN(131, "stio_1_dat2"),
PINCTRL_PIN(132, "stio_1_dat3"),
PINCTRL_PIN(133, "stio_2_clk"),
PINCTRL_PIN(134, "stio_2_cmd"),
PINCTRL_PIN(135, "stio_2_dat0"),
PINCTRL_PIN(136, "stio_2_dat1"),
PINCTRL_PIN(137, "stio_2_dat2"),
PINCTRL_PIN(138, "stio_2_dat3"),
PINCTRL_PIN(139, "coms_int0"),
PINCTRL_PIN(140, "coms_int1"),
PINCTRL_PIN(141, "coms_int2"),
PINCTRL_PIN(142, "coms_int3"),
PINCTRL_PIN(143, "ded_gpio4"),
PINCTRL_PIN(144, "ded_gpio5"),
PINCTRL_PIN(145, "ded_gpio6"),
PINCTRL_PIN(146, "ded_gpio7"),
PINCTRL_PIN(147, "i2s_0_clk"),
PINCTRL_PIN(148, "i2s_0_fs"),
PINCTRL_PIN(149, "i2s_0_rxd"),
PINCTRL_PIN(150, "i2s_0_txd"),
PINCTRL_PIN(151, "i2s_1_clk"),
PINCTRL_PIN(152, "i2s_1_fs"),
PINCTRL_PIN(153, "i2s_1_rxd"),
PINCTRL_PIN(154, "i2s_1_txd"),
PINCTRL_PIN(155, "mslim_1_bclk"),
PINCTRL_PIN(156, "mslim_1_bdat"),
PINCTRL_PIN(157, "resetout_b"),
PINCTRL_PIN(158, "spi_2_clk"),
PINCTRL_PIN(159, "spi_2_sdi"),
PINCTRL_PIN(160, "spi_2_sdo"),
PINCTRL_PIN(161, "spi_2_ss0"),
PINCTRL_PIN(162, "spi_2_ss1"),
PINCTRL_PIN(163, "spi_3_clk"),
PINCTRL_PIN(164, "spi_3_sdi"),
PINCTRL_PIN(165, "spi_3_sdo"),
PINCTRL_PIN(166, "spi_3_ss0"),
PINCTRL_PIN(167, "spi_3_ss1"),
PINCTRL_PIN(168, "uart_0_cts"),
PINCTRL_PIN(169, "uart_0_rts"),
PINCTRL_PIN(170, "uart_0_rx"),
PINCTRL_PIN(171, "uart_0_tx"),
PINCTRL_PIN(172, "uart_1_rx"),
PINCTRL_PIN(173, "uart_1_sd"),
PINCTRL_PIN(174, "uart_1_tx"),
PINCTRL_PIN(175, "uart_2_rx"),
PINCTRL_PIN(176, "uart_2_tx"),
PINCTRL_PIN(177, "aclkph"),
PINCTRL_PIN(178, "dclkph"),
PINCTRL_PIN(179, "dsiclkph"),
PINCTRL_PIN(180, "ierr"),
PINCTRL_PIN(181, "jtag_tckc"),
PINCTRL_PIN(182, "jtag_tdic"),
PINCTRL_PIN(183, "jtag_tdoc"),
PINCTRL_PIN(184, "jtag_tmsc"),
PINCTRL_PIN(185, "jtag_trst_b"),
PINCTRL_PIN(186, "lclkph"),
PINCTRL_PIN(187, "lfhclkph"),
PINCTRL_PIN(188, "osc_clk_ctrl0"),
PINCTRL_PIN(189, "osc_clk_ctrl1"),
PINCTRL_PIN(190, "osc_clk_out0"),
PINCTRL_PIN(191, "osc_clk_out1"),
PINCTRL_PIN(192, "osc_clk_out2"),
PINCTRL_PIN(193, "osc_clk_out3"),
PINCTRL_PIN(194, "prochot_b"),
PINCTRL_PIN(195, "thermtrip_b"),
PINCTRL_PIN(196, "uclkph"),
PINCTRL_PIN(197, "ded_gpio31"),
PINCTRL_PIN(198, "ded_gpio32"),
PINCTRL_PIN(199, "ded_gpio33"),
PINCTRL_PIN(200, "hdmi_cec"),
PINCTRL_PIN(201, "i2c_3_scl_hdmi_ddc"),
PINCTRL_PIN(202, "i2c_3_sda_hdmi_ddc"),
PINCTRL_PIN(203, "i2c_0_scl"),
PINCTRL_PIN(204, "i2c_0_sda"),
PINCTRL_PIN(205, "i2c_1_scl"),
PINCTRL_PIN(206, "i2c_1_sda"),
PINCTRL_PIN(207, "i2c_2_scl"),
PINCTRL_PIN(208, "i2c_2_sda"),
PINCTRL_PIN(209, "spi_1_clk"),
PINCTRL_PIN(210, "spi_1_sdi"),
PINCTRL_PIN(211, "spi_1_sdo"),
PINCTRL_PIN(212, "spi_1_ss0"),
PINCTRL_PIN(213, "spi_1_ss1"),
PINCTRL_PIN(214, "spi_1_ss2"),
PINCTRL_PIN(215, "spi_1_ss3"),
PINCTRL_PIN(216, "spi_1_ss4"),
};
struct intel_mid_pinctrl_drvdata {
struct device *dev;
struct pinctrl_dev *pctl;
struct pinstruct_t *pin_t;
int pin_num;
};
#define DRIVER_NAME "intel-mid-pinctrl"
struct ctp_pin_group {
const char *name;
const unsigned int *pins;
const unsigned num_pins;
};
static const struct ctp_pin_group ctp_pin_groups[] = {
/* Need to be filled */
};
static int ctp_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
{
if (selector >= ARRAY_SIZE(ctp_pin_groups))
return -EINVAL;
return 0;
}
static const char *ctp_get_group_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
if (selector >= ARRAY_SIZE(ctp_pin_groups))
return NULL;
return ctp_pin_groups[selector].name;
}
static int ctp_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
const unsigned **pins,
unsigned *num_pins)
{
if (selector >= ARRAY_SIZE(ctp_pin_groups))
return -EINVAL;
*pins = ctp_pin_groups[selector].pins;
*num_pins = ctp_pin_groups[selector].num_pins;
return 0;
}
static void ctp_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
unsigned offset)
{
seq_printf(s, " " DRIVER_NAME);
}
static struct pinctrl_ops ctp_pctrl_ops = {
.list_groups = ctp_list_groups,
.get_group_name = ctp_get_group_name,
.get_group_pins = ctp_get_group_pins,
.pin_dbg_show = ctp_pin_dbg_show,
};
int ctp_pin_config_get(struct pinctrl_dev *pctldev,
unsigned pin,
unsigned long *config)
{
struct intel_mid_pinctrl_drvdata *impd =
pinctrl_dev_get_drvdata(pctldev);
u32 flis_addr, off, data, mask;
int ret, pos;
/* bit[11:8] indicate the configuration type,
* bit[7:0] indicate the value
*/
u8 val = *config & 0xFF;
u8 type = (*config & 0xF00) >> 8;
enum pin_config_param param = (enum pin_config_param) type;
if (pin < 0 || pin >= impd->pin_num)
return -EINVAL;
if (impd->pin_t[pin].valid == false)
return -EINVAL;
flis_addr = impd->pin_t[pin].bus_address;
switch (param) {
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_BIAS_PULL_DOWN:
off = impd->pin_t[pin].pullup_offset;
pos = impd->pin_t[pin].pullup_lsb_pos;
mask = PULL_MASK;
break;
case PIN_CONFIG_MUX:
off = impd->pin_t[pin].direction_offset;
pos = impd->pin_t[pin].direction_lsb_pos;
mask = MUX_MASK;
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
off = impd->pin_t[pin].open_drain_offset;
pos = impd->pin_t[pin].open_drain_bit;
mask = OPEN_DRAIN_MASK;
break;
default:
dev_err(impd->dev, "illegal configuration requested\n");
return -EINVAL;
}
ret = intel_scu_ipc_read_shim(&data, flis_addr, off);
if (ret) {
dev_err(impd->dev, "read shim failed, addr = 0x%x, off = 0x%x\n",
flis_addr, off);
return ret;
}
val = (data >> pos) & mask;
*config &= (~0xFF);
*config |= val;
pr_debug("read: data = 0x%x, val = 0x%x\n", data, val);
return 0;
}
int ctp_pin_config_set(struct pinctrl_dev *pctldev,
unsigned pin,
unsigned long config)
{
struct intel_mid_pinctrl_drvdata *impd
= pinctrl_dev_get_drvdata(pctldev);
u32 flis_addr, off, data, mask;
int ret, pos;
/* bit[11:8] indicate the configuration type,
* bit[7:0] indicate the value
*/
u8 val = config & 0xFF;
u8 type = (config & 0xF00) >> 8;
enum pin_config_param param = (enum pin_config_param) type;
if (pin < 0 || pin >= impd->pin_num)
return -EINVAL;
if (impd->pin_t[pin].valid == false)
return -EINVAL;
flis_addr = impd->pin_t[pin].bus_address;
switch (param) {
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_BIAS_PULL_DOWN:
off = impd->pin_t[pin].pullup_offset;
pos = impd->pin_t[pin].pullup_lsb_pos;
mask = (PULL_MASK << pos);
break;
case PIN_CONFIG_MUX:
off = impd->pin_t[pin].direction_offset;
pos = impd->pin_t[pin].direction_lsb_pos;
mask = (MUX_MASK << pos);
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
off = impd->pin_t[pin].open_drain_offset;
pos = impd->pin_t[pin].open_drain_bit;
mask = (OPEN_DRAIN_MASK << pos);
break;
default:
dev_err(impd->dev, "illegal configuration requested\n");
return -EINVAL;
}
data = (val << pos);
pr_debug("addr = 0x%x, off = 0x%x, pos = %d, mask = 0x%x, data = 0x%x\n",
flis_addr, off, pos, mask, data);
ret = intel_scu_ipc_update_shim(data, mask, flis_addr, off);
if (ret) {
dev_err(impd->dev, "update shim failed\n");
return ret;
}
return 0;
}
static struct pinconf_ops ctp_pconf_ops = {
.is_generic = true,
.pin_config_get = ctp_pin_config_get,
.pin_config_set = ctp_pin_config_set,
};
static struct pinctrl_desc intel_mid_pin_descs[] = {
[ctp_pin_desc] = {
.name = "ctp_pinctrl",
.pins = ctp_pins,
.npins = ARRAY_SIZE(ctp_pins),
.pctlops = &ctp_pctrl_ops,
.confops = &ctp_pconf_ops,
.owner = THIS_MODULE,
},
[mrfl_pin_desc] = {
.name = "mrfl_pinctrl",
},
};
static int intel_mid_pinctrl_probe(struct platform_device *pdev)
{
int ret;
struct intel_mid_pinctrl_drvdata *impd;
struct intel_mid_pinctrl_platform_data *pdata =
pdev->dev.platform_data;
int i;
if (!pdata) {
dev_err(&pdev->dev, "No pinctrl platform data\n");
ret = -EINVAL;
goto out;
}
/* Create state holders etc for this driver */
impd = devm_kzalloc(&pdev->dev, sizeof(*impd), GFP_KERNEL);
if (!impd)
return -ENOMEM;
impd->dev = &pdev->dev;
impd->pin_t = pdata->pin_t;
impd->pin_num = pdata->pin_num;
for (i = 0; i < ARRAY_SIZE(intel_mid_pin_descs); i++) {
if (!strcmp(pdata->name, intel_mid_pin_descs[i].name)) {
impd->pctl = pinctrl_register(&intel_mid_pin_descs[i],
&pdev->dev, impd);
if (!impd->pctl) {
dev_err(&pdev->dev,
"could not register %s pinctrl driver\n",
pdata->name);
ret = -EINVAL;
goto err1;
}
break;
}
}
if (i == ARRAY_SIZE(intel_mid_pin_descs)) {
dev_err(&pdev->dev, "could not find match of desc\n");
ret = -ENODEV;
goto err1;
}
platform_set_drvdata(pdev, impd);
dev_info(&pdev->dev, "initialized Intel MID pinctrl driver\n");
return 0;
err1:
devm_kfree(&pdev->dev, impd);
out:
return ret;
}
static int intel_mid_pinctrl_remove(struct platform_device *pdev)
{
struct intel_mid_pinctrl_drvdata *impd = platform_get_drvdata(pdev);
pinctrl_unregister(impd->pctl);
platform_set_drvdata(pdev, NULL);
devm_kfree(&pdev->dev, impd);
return 0;
}
static struct platform_driver intel_mid_pinctrl_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
.probe = intel_mid_pinctrl_probe,
.remove = intel_mid_pinctrl_remove,
};
static int __init intel_mid_pinctrl_init(void)
{
return platform_driver_register(&intel_mid_pinctrl_driver);
}
arch_initcall(intel_mid_pinctrl_init);
static void __exit intel_mid_pinctrl_exit(void)
{
platform_driver_unregister(&intel_mid_pinctrl_driver);
}
module_exit(intel_mid_pinctrl_exit);
MODULE_DESCRIPTION("Intel MID pin control driver");
MODULE_LICENSE("GPL v2");