diff options
Diffstat (limited to 'drivers/misc')
| -rw-r--r-- | drivers/misc/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/misc/Makefile | 3 | ||||
| -rw-r--r-- | drivers/misc/apds990x.c | 2 | ||||
| -rw-r--r-- | drivers/misc/atmel-ssc.c | 2 | ||||
| -rw-r--r-- | drivers/misc/atmel_pwm.c | 2 | ||||
| -rw-r--r-- | drivers/misc/cb710/sgbuf2.c | 2 | ||||
| -rw-r--r-- | drivers/misc/cs5535-mfgpt.c | 2 | ||||
| -rw-r--r-- | drivers/misc/eeprom/Kconfig | 25 | ||||
| -rw-r--r-- | drivers/misc/eeprom/Makefile | 2 | ||||
| -rw-r--r-- | drivers/misc/eeprom/digsy_mtc_eeprom.c | 85 | ||||
| -rw-r--r-- | drivers/misc/eeprom/eeprom_93xx46.c | 410 | ||||
| -rw-r--r-- | drivers/misc/fsa9480.c | 557 | ||||
| -rw-r--r-- | drivers/misc/ioc4.c | 2 | ||||
| -rw-r--r-- | drivers/misc/lkdtm.c | 8 | ||||
| -rw-r--r-- | drivers/misc/pch_phub.c | 9 | ||||
| -rw-r--r-- | drivers/misc/phantom.c | 2 | ||||
| -rw-r--r-- | drivers/misc/pti.c | 116 | ||||
| -rw-r--r-- | drivers/misc/sgi-xp/xpnet.c | 6 | ||||
| -rw-r--r-- | drivers/misc/spear13xx_pcie_gadget.c | 2 | ||||
| -rw-r--r-- | drivers/misc/ti-st/st_core.c | 2 | ||||
| -rw-r--r-- | drivers/misc/ti-st/st_kim.c | 8 | ||||
| -rw-r--r-- | drivers/misc/vmw_balloon.c | 31 | 
22 files changed, 1205 insertions, 85 deletions
| diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 4e349cd98bcf..0a4d86c6c4a4 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -245,8 +245,7 @@ config SGI_XP  config CS5535_MFGPT  	tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support" -	depends on PCI -	depends on X86 +	depends on PCI && X86 && MFD_CS5535  	default n  	help  	  This driver provides access to MFGPT functionality for other @@ -490,6 +489,15 @@ config PCH_PHUB  	  To compile this driver as a module, choose M here: the module will  	  be called pch_phub. +config USB_SWITCH_FSA9480 +	tristate "FSA9480 USB Switch" +	depends on I2C +	help +	  The FSA9480 is a USB port accessory detector and switch. +	  The FSA9480 is fully controlled using I2C and enables USB data, +	  stereo and mono audio, video, microphone and UART data to use +	  a common connector port. +  source "drivers/misc/c2port/Kconfig"  source "drivers/misc/eeprom/Kconfig"  source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5f03172cc0b5..8f3efb68a141 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_IBM_ASM)		+= ibmasm/  obj-$(CONFIG_AD525X_DPOT)	+= ad525x_dpot.o  obj-$(CONFIG_AD525X_DPOT_I2C)	+= ad525x_dpot-i2c.o  obj-$(CONFIG_AD525X_DPOT_SPI)	+= ad525x_dpot-spi.o -0bj-$(CONFIG_INTEL_MID_PTI)	+= pti.o +obj-$(CONFIG_INTEL_MID_PTI)	+= pti.o  obj-$(CONFIG_ATMEL_PWM)		+= atmel_pwm.o  obj-$(CONFIG_ATMEL_SSC)		+= atmel-ssc.o  obj-$(CONFIG_ATMEL_TCLIB)	+= atmel_tclib.o @@ -46,3 +46,4 @@ obj-y				+= ti-st/  obj-$(CONFIG_AB8500_PWM)	+= ab8500-pwm.o  obj-y				+= lis3lv02d/  obj-y				+= carma/ +obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index 200311fea369..e2a52e5cf449 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -609,6 +609,7 @@ static int apds990x_detect(struct apds990x_chip *chip)  	return ret;  } +#if defined(CONFIG_PM) || defined(CONFIG_PM_RUNTIME)  static int apds990x_chip_on(struct apds990x_chip *chip)  {  	int err	 = regulator_bulk_enable(ARRAY_SIZE(chip->regs), @@ -624,6 +625,7 @@ static int apds990x_chip_on(struct apds990x_chip *chip)  	apds990x_mode_on(chip);  	return 0;  } +#endif  static int apds990x_chip_off(struct apds990x_chip *chip)  { diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 4afffe610f99..769a4e8e10dc 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -95,7 +95,7 @@ static int __init ssc_probe(struct platform_device *pdev)  	}  	ssc->pdev = pdev; -	ssc->regs = ioremap(regs->start, regs->end - regs->start + 1); +	ssc->regs = ioremap(regs->start, resource_size(regs));  	if (!ssc->regs) {  		dev_dbg(&pdev->dev, "ioremap failed\n");  		retval = -EINVAL; diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c index 0f3fb4f03bdf..28f5aaa19d4a 100644 --- a/drivers/misc/atmel_pwm.c +++ b/drivers/misc/atmel_pwm.c @@ -329,7 +329,7 @@ static int __init pwm_probe(struct platform_device *pdev)  	p->pdev = pdev;  	p->mask = *mp;  	p->irq = irq; -	p->base = ioremap(r->start, r->end - r->start + 1); +	p->base = ioremap(r->start, resource_size(r));  	if (!p->base)  		goto fail;  	p->clk = clk_get(&pdev->dev, "pwm_clk"); diff --git a/drivers/misc/cb710/sgbuf2.c b/drivers/misc/cb710/sgbuf2.c index d019746551f3..2a40d0efdff5 100644 --- a/drivers/misc/cb710/sgbuf2.c +++ b/drivers/misc/cb710/sgbuf2.c @@ -47,7 +47,7 @@ static uint32_t sg_dwiter_read_buffer(struct sg_mapping_iter *miter)  static inline bool needs_unaligned_copy(const void *ptr)  { -#ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS  	return false;  #else  	return ((ptr - NULL) & 3) != 0; diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index e01e08c8c88b..bc685bfc4c33 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c @@ -174,7 +174,7 @@ struct cs5535_mfgpt_timer *cs5535_mfgpt_alloc_timer(int timer_nr, int domain)  		timer_nr = t < max ? (int) t : -1;  	} else {  		/* check if the requested timer's available */ -		if (test_bit(timer_nr, mfgpt->avail)) +		if (!test_bit(timer_nr, mfgpt->avail))  			timer_nr = -1;  	} diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 9118613af321..26cf12ca7f50 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -70,4 +70,29 @@ config EEPROM_93CX6  	  If unsure, say N. +config EEPROM_93XX46 +	tristate "Microwire EEPROM 93XX46 support" +	depends on SPI && SYSFS +	help +	  Driver for the microwire EEPROM chipsets 93xx46x. The driver +	  supports both read and write commands and also the command to +	  erase the whole EEPROM. + +	  This driver can also be built as a module.  If so, the module +	  will be called eeprom_93xx46. + +	  If unsure, say N. + +config EEPROM_DIGSY_MTC_CFG +	bool "DigsyMTC display configuration EEPROMs device" +	depends on PPC_MPC5200_GPIO && GPIOLIB && SPI_GPIO +	help +	  This option enables access to display configuration EEPROMs +	  on digsy_mtc board. You have to additionally select Microwire +	  EEPROM 93XX46 driver. sysfs entries will be created for that +	  EEPROM allowing to read/write the configuration data or to +	  erase the whole EEPROM. + +	  If unsure, say N. +  endmenu diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index df3d68ffa9d1..fc1e81d29267 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile @@ -3,3 +3,5 @@ obj-$(CONFIG_EEPROM_AT25)	+= at25.o  obj-$(CONFIG_EEPROM_LEGACY)	+= eeprom.o  obj-$(CONFIG_EEPROM_MAX6875)	+= max6875.o  obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o +obj-$(CONFIG_EEPROM_93XX46)	+= eeprom_93xx46.o +obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o diff --git a/drivers/misc/eeprom/digsy_mtc_eeprom.c b/drivers/misc/eeprom/digsy_mtc_eeprom.c new file mode 100644 index 000000000000..66d9e1baeae5 --- /dev/null +++ b/drivers/misc/eeprom/digsy_mtc_eeprom.c @@ -0,0 +1,85 @@ +/* + * EEPROMs access control driver for display configuration EEPROMs + * on DigsyMTC board. + * + * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_gpio.h> +#include <linux/eeprom_93xx46.h> + +#define GPIO_EEPROM_CLK		216 +#define GPIO_EEPROM_CS		210 +#define GPIO_EEPROM_DI		217 +#define GPIO_EEPROM_DO		249 +#define GPIO_EEPROM_OE		255 +#define EE_SPI_BUS_NUM	1 + +static void digsy_mtc_op_prepare(void *p) +{ +	/* enable */ +	gpio_set_value(GPIO_EEPROM_OE, 0); +} + +static void digsy_mtc_op_finish(void *p) +{ +	/* disable */ +	gpio_set_value(GPIO_EEPROM_OE, 1); +} + +struct eeprom_93xx46_platform_data digsy_mtc_eeprom_data = { +	.flags		= EE_ADDR8, +	.prepare	= digsy_mtc_op_prepare, +	.finish		= digsy_mtc_op_finish, +}; + +static struct spi_gpio_platform_data eeprom_spi_gpio_data = { +	.sck		= GPIO_EEPROM_CLK, +	.mosi		= GPIO_EEPROM_DI, +	.miso		= GPIO_EEPROM_DO, +	.num_chipselect	= 1, +}; + +static struct platform_device digsy_mtc_eeprom = { +	.name	= "spi_gpio", +	.id	= EE_SPI_BUS_NUM, +	.dev	= { +		.platform_data	= &eeprom_spi_gpio_data, +	}, +}; + +static struct spi_board_info digsy_mtc_eeprom_info[] __initdata = { +	{ +		.modalias		= "93xx46", +		.max_speed_hz		= 1000000, +		.bus_num		= EE_SPI_BUS_NUM, +		.chip_select		= 0, +		.mode			= SPI_MODE_0, +		.controller_data	= (void *)GPIO_EEPROM_CS, +		.platform_data		= &digsy_mtc_eeprom_data, +	}, +}; + +static int __init digsy_mtc_eeprom_devices_init(void) +{ +	int ret; + +	ret = gpio_request_one(GPIO_EEPROM_OE, GPIOF_OUT_INIT_HIGH, +				"93xx46 EEPROMs OE"); +	if (ret) { +		pr_err("can't request gpio %d\n", GPIO_EEPROM_OE); +		return ret; +	} +	spi_register_board_info(digsy_mtc_eeprom_info, +				ARRAY_SIZE(digsy_mtc_eeprom_info)); +	return platform_device_register(&digsy_mtc_eeprom); +} +device_initcall(digsy_mtc_eeprom_devices_init); diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c new file mode 100644 index 000000000000..0c7ebb1e19e5 --- /dev/null +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -0,0 +1,410 @@ +/* + * Driver for 93xx46 EEPROMs + * + * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/sysfs.h> +#include <linux/eeprom_93xx46.h> + +#define OP_START	0x4 +#define OP_WRITE	(OP_START | 0x1) +#define OP_READ		(OP_START | 0x2) +#define ADDR_EWDS	0x00 +#define ADDR_ERAL	0x20 +#define ADDR_EWEN	0x30 + +struct eeprom_93xx46_dev { +	struct spi_device *spi; +	struct eeprom_93xx46_platform_data *pdata; +	struct bin_attribute bin; +	struct mutex lock; +	int addrlen; +}; + +static ssize_t +eeprom_93xx46_bin_read(struct file *filp, struct kobject *kobj, +		       struct bin_attribute *bin_attr, +		       char *buf, loff_t off, size_t count) +{ +	struct eeprom_93xx46_dev *edev; +	struct device *dev; +	struct spi_message m; +	struct spi_transfer t[2]; +	int bits, ret; +	u16 cmd_addr; + +	dev = container_of(kobj, struct device, kobj); +	edev = dev_get_drvdata(dev); + +	if (unlikely(off >= edev->bin.size)) +		return 0; +	if ((off + count) > edev->bin.size) +		count = edev->bin.size - off; +	if (unlikely(!count)) +		return count; + +	cmd_addr = OP_READ << edev->addrlen; + +	if (edev->addrlen == 7) { +		cmd_addr |= off & 0x7f; +		bits = 10; +	} else { +		cmd_addr |= off & 0x3f; +		bits = 9; +	} + +	dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n", +		cmd_addr, edev->spi->max_speed_hz); + +	spi_message_init(&m); +	memset(t, 0, sizeof(t)); + +	t[0].tx_buf = (char *)&cmd_addr; +	t[0].len = 2; +	t[0].bits_per_word = bits; +	spi_message_add_tail(&t[0], &m); + +	t[1].rx_buf = buf; +	t[1].len = count; +	t[1].bits_per_word = 8; +	spi_message_add_tail(&t[1], &m); + +	mutex_lock(&edev->lock); + +	if (edev->pdata->prepare) +		edev->pdata->prepare(edev); + +	ret = spi_sync(edev->spi, &m); +	/* have to wait at least Tcsl ns */ +	ndelay(250); +	if (ret) { +		dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n", +			count, (int)off, ret); +	} + +	if (edev->pdata->finish) +		edev->pdata->finish(edev); + +	mutex_unlock(&edev->lock); +	return ret ? : count; +} + +static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) +{ +	struct spi_message m; +	struct spi_transfer t; +	int bits, ret; +	u16 cmd_addr; + +	cmd_addr = OP_START << edev->addrlen; +	if (edev->addrlen == 7) { +		cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << 1; +		bits = 10; +	} else { +		cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS); +		bits = 9; +	} + +	dev_dbg(&edev->spi->dev, "ew cmd 0x%04x\n", cmd_addr); + +	spi_message_init(&m); +	memset(&t, 0, sizeof(t)); + +	t.tx_buf = &cmd_addr; +	t.len = 2; +	t.bits_per_word = bits; +	spi_message_add_tail(&t, &m); + +	mutex_lock(&edev->lock); + +	if (edev->pdata->prepare) +		edev->pdata->prepare(edev); + +	ret = spi_sync(edev->spi, &m); +	/* have to wait at least Tcsl ns */ +	ndelay(250); +	if (ret) +		dev_err(&edev->spi->dev, "erase/write %sable error %d\n", +			is_on ? "en" : "dis", ret); + +	if (edev->pdata->finish) +		edev->pdata->finish(edev); + +	mutex_unlock(&edev->lock); +	return ret; +} + +static ssize_t +eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev, +			 const char *buf, unsigned off) +{ +	struct spi_message m; +	struct spi_transfer t[2]; +	int bits, data_len, ret; +	u16 cmd_addr; + +	cmd_addr = OP_WRITE << edev->addrlen; + +	if (edev->addrlen == 7) { +		cmd_addr |= off & 0x7f; +		bits = 10; +		data_len = 1; +	} else { +		cmd_addr |= off & 0x3f; +		bits = 9; +		data_len = 2; +	} + +	dev_dbg(&edev->spi->dev, "write cmd 0x%x\n", cmd_addr); + +	spi_message_init(&m); +	memset(t, 0, sizeof(t)); + +	t[0].tx_buf = (char *)&cmd_addr; +	t[0].len = 2; +	t[0].bits_per_word = bits; +	spi_message_add_tail(&t[0], &m); + +	t[1].tx_buf = buf; +	t[1].len = data_len; +	t[1].bits_per_word = 8; +	spi_message_add_tail(&t[1], &m); + +	ret = spi_sync(edev->spi, &m); +	/* have to wait program cycle time Twc ms */ +	mdelay(6); +	return ret; +} + +static ssize_t +eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj, +			struct bin_attribute *bin_attr, +			char *buf, loff_t off, size_t count) +{ +	struct eeprom_93xx46_dev *edev; +	struct device *dev; +	int i, ret, step = 1; + +	dev = container_of(kobj, struct device, kobj); +	edev = dev_get_drvdata(dev); + +	if (unlikely(off >= edev->bin.size)) +		return 0; +	if ((off + count) > edev->bin.size) +		count = edev->bin.size - off; +	if (unlikely(!count)) +		return count; + +	/* only write even number of bytes on 16-bit devices */ +	if (edev->addrlen == 6) { +		step = 2; +		count &= ~1; +	} + +	/* erase/write enable */ +	ret = eeprom_93xx46_ew(edev, 1); +	if (ret) +		return ret; + +	mutex_lock(&edev->lock); + +	if (edev->pdata->prepare) +		edev->pdata->prepare(edev); + +	for (i = 0; i < count; i += step) { +		ret = eeprom_93xx46_write_word(edev, &buf[i], off + i); +		if (ret) { +			dev_err(&edev->spi->dev, "write failed at %d: %d\n", +				(int)off + i, ret); +			break; +		} +	} + +	if (edev->pdata->finish) +		edev->pdata->finish(edev); + +	mutex_unlock(&edev->lock); + +	/* erase/write disable */ +	eeprom_93xx46_ew(edev, 0); +	return ret ? : count; +} + +static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev) +{ +	struct eeprom_93xx46_platform_data *pd = edev->pdata; +	struct spi_message m; +	struct spi_transfer t; +	int bits, ret; +	u16 cmd_addr; + +	cmd_addr = OP_START << edev->addrlen; +	if (edev->addrlen == 7) { +		cmd_addr |= ADDR_ERAL << 1; +		bits = 10; +	} else { +		cmd_addr |= ADDR_ERAL; +		bits = 9; +	} + +	spi_message_init(&m); +	memset(&t, 0, sizeof(t)); + +	t.tx_buf = &cmd_addr; +	t.len = 2; +	t.bits_per_word = bits; +	spi_message_add_tail(&t, &m); + +	mutex_lock(&edev->lock); + +	if (edev->pdata->prepare) +		edev->pdata->prepare(edev); + +	ret = spi_sync(edev->spi, &m); +	if (ret) +		dev_err(&edev->spi->dev, "erase error %d\n", ret); +	/* have to wait erase cycle time Tec ms */ +	mdelay(6); + +	if (pd->finish) +		pd->finish(edev); + +	mutex_unlock(&edev->lock); +	return ret; +} + +static ssize_t eeprom_93xx46_store_erase(struct device *dev, +					 struct device_attribute *attr, +					 const char *buf, size_t count) +{ +	struct eeprom_93xx46_dev *edev = dev_get_drvdata(dev); +	int erase = 0, ret; + +	sscanf(buf, "%d", &erase); +	if (erase) { +		ret = eeprom_93xx46_ew(edev, 1); +		if (ret) +			return ret; +		ret = eeprom_93xx46_eral(edev); +		if (ret) +			return ret; +		ret = eeprom_93xx46_ew(edev, 0); +		if (ret) +			return ret; +	} +	return count; +} +static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase); + +static int __devinit eeprom_93xx46_probe(struct spi_device *spi) +{ +	struct eeprom_93xx46_platform_data *pd; +	struct eeprom_93xx46_dev *edev; +	int err; + +	pd = spi->dev.platform_data; +	if (!pd) { +		dev_err(&spi->dev, "missing platform data\n"); +		return -ENODEV; +	} + +	edev = kzalloc(sizeof(*edev), GFP_KERNEL); +	if (!edev) +		return -ENOMEM; + +	if (pd->flags & EE_ADDR8) +		edev->addrlen = 7; +	else if (pd->flags & EE_ADDR16) +		edev->addrlen = 6; +	else { +		dev_err(&spi->dev, "unspecified address type\n"); +		err = -EINVAL; +		goto fail; +	} + +	mutex_init(&edev->lock); + +	edev->spi = spi_dev_get(spi); +	edev->pdata = pd; + +	sysfs_bin_attr_init(&edev->bin); +	edev->bin.attr.name = "eeprom"; +	edev->bin.attr.mode = S_IRUSR; +	edev->bin.read = eeprom_93xx46_bin_read; +	edev->bin.size = 128; +	if (!(pd->flags & EE_READONLY)) { +		edev->bin.write = eeprom_93xx46_bin_write; +		edev->bin.attr.mode |= S_IWUSR; +	} + +	err = sysfs_create_bin_file(&spi->dev.kobj, &edev->bin); +	if (err) +		goto fail; + +	dev_info(&spi->dev, "%d-bit eeprom %s\n", +		(pd->flags & EE_ADDR8) ? 8 : 16, +		(pd->flags & EE_READONLY) ? "(readonly)" : ""); + +	if (!(pd->flags & EE_READONLY)) { +		if (device_create_file(&spi->dev, &dev_attr_erase)) +			dev_err(&spi->dev, "can't create erase interface\n"); +	} + +	dev_set_drvdata(&spi->dev, edev); +	return 0; +fail: +	kfree(edev); +	return err; +} + +static int __devexit eeprom_93xx46_remove(struct spi_device *spi) +{ +	struct eeprom_93xx46_dev *edev = dev_get_drvdata(&spi->dev); + +	if (!(edev->pdata->flags & EE_READONLY)) +		device_remove_file(&spi->dev, &dev_attr_erase); + +	sysfs_remove_bin_file(&spi->dev.kobj, &edev->bin); +	dev_set_drvdata(&spi->dev, NULL); +	kfree(edev); +	return 0; +} + +static struct spi_driver eeprom_93xx46_driver = { +	.driver = { +		.name	= "93xx46", +		.owner	= THIS_MODULE, +	}, +	.probe		= eeprom_93xx46_probe, +	.remove		= __devexit_p(eeprom_93xx46_remove), +}; + +static int __init eeprom_93xx46_init(void) +{ +	return spi_register_driver(&eeprom_93xx46_driver); +} +module_init(eeprom_93xx46_init); + +static void __exit eeprom_93xx46_exit(void) +{ +	spi_unregister_driver(&eeprom_93xx46_driver); +} +module_exit(eeprom_93xx46_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Driver for 93xx46 EEPROMs"); +MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>"); +MODULE_ALIAS("spi:93xx46"); diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c new file mode 100644 index 000000000000..5325a7e70dcf --- /dev/null +++ b/drivers/misc/fsa9480.c @@ -0,0 +1,557 @@ +/* + * fsa9480.c - FSA9480 micro USB switch device driver + * + * Copyright (C) 2010 Samsung Electronics + * Minkyu Kang <mk7.kang@samsung.com> + * Wonguk Jeong <wonguk.jeong@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/platform_data/fsa9480.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> + +/* FSA9480 I2C registers */ +#define FSA9480_REG_DEVID		0x01 +#define FSA9480_REG_CTRL		0x02 +#define FSA9480_REG_INT1		0x03 +#define FSA9480_REG_INT2		0x04 +#define FSA9480_REG_INT1_MASK		0x05 +#define FSA9480_REG_INT2_MASK		0x06 +#define FSA9480_REG_ADC			0x07 +#define FSA9480_REG_TIMING1		0x08 +#define FSA9480_REG_TIMING2		0x09 +#define FSA9480_REG_DEV_T1		0x0a +#define FSA9480_REG_DEV_T2		0x0b +#define FSA9480_REG_BTN1		0x0c +#define FSA9480_REG_BTN2		0x0d +#define FSA9480_REG_CK			0x0e +#define FSA9480_REG_CK_INT1		0x0f +#define FSA9480_REG_CK_INT2		0x10 +#define FSA9480_REG_CK_INTMASK1		0x11 +#define FSA9480_REG_CK_INTMASK2		0x12 +#define FSA9480_REG_MANSW1		0x13 +#define FSA9480_REG_MANSW2		0x14 + +/* Control */ +#define CON_SWITCH_OPEN		(1 << 4) +#define CON_RAW_DATA		(1 << 3) +#define CON_MANUAL_SW		(1 << 2) +#define CON_WAIT		(1 << 1) +#define CON_INT_MASK		(1 << 0) +#define CON_MASK		(CON_SWITCH_OPEN | CON_RAW_DATA | \ +				CON_MANUAL_SW | CON_WAIT) + +/* Device Type 1 */ +#define DEV_USB_OTG		(1 << 7) +#define DEV_DEDICATED_CHG	(1 << 6) +#define DEV_USB_CHG		(1 << 5) +#define DEV_CAR_KIT		(1 << 4) +#define DEV_UART		(1 << 3) +#define DEV_USB			(1 << 2) +#define DEV_AUDIO_2		(1 << 1) +#define DEV_AUDIO_1		(1 << 0) + +#define DEV_T1_USB_MASK		(DEV_USB_OTG | DEV_USB) +#define DEV_T1_UART_MASK	(DEV_UART) +#define DEV_T1_CHARGER_MASK	(DEV_DEDICATED_CHG | DEV_USB_CHG) + +/* Device Type 2 */ +#define DEV_AV			(1 << 6) +#define DEV_TTY			(1 << 5) +#define DEV_PPD			(1 << 4) +#define DEV_JIG_UART_OFF	(1 << 3) +#define DEV_JIG_UART_ON		(1 << 2) +#define DEV_JIG_USB_OFF		(1 << 1) +#define DEV_JIG_USB_ON		(1 << 0) + +#define DEV_T2_USB_MASK		(DEV_JIG_USB_OFF | DEV_JIG_USB_ON) +#define DEV_T2_UART_MASK	(DEV_JIG_UART_OFF | DEV_JIG_UART_ON) +#define DEV_T2_JIG_MASK		(DEV_JIG_USB_OFF | DEV_JIG_USB_ON | \ +				DEV_JIG_UART_OFF | DEV_JIG_UART_ON) + +/* + * Manual Switch + * D- [7:5] / D+ [4:2] + * 000: Open all / 001: USB / 010: AUDIO / 011: UART / 100: V_AUDIO + */ +#define SW_VAUDIO		((4 << 5) | (4 << 2)) +#define SW_UART			((3 << 5) | (3 << 2)) +#define SW_AUDIO		((2 << 5) | (2 << 2)) +#define SW_DHOST		((1 << 5) | (1 << 2)) +#define SW_AUTO			((0 << 5) | (0 << 2)) + +/* Interrupt 1 */ +#define INT_DETACH		(1 << 1) +#define INT_ATTACH		(1 << 0) + +struct fsa9480_usbsw { +	struct i2c_client		*client; +	struct fsa9480_platform_data	*pdata; +	int				dev1; +	int				dev2; +	int				mansw; +}; + +static struct fsa9480_usbsw *chip; + +static int fsa9480_write_reg(struct i2c_client *client, +		int reg, int value) +{ +	int ret; + +	ret = i2c_smbus_write_byte_data(client, reg, value); + +	if (ret < 0) +		dev_err(&client->dev, "%s: err %d\n", __func__, ret); + +	return ret; +} + +static int fsa9480_read_reg(struct i2c_client *client, int reg) +{ +	int ret; + +	ret = i2c_smbus_read_byte_data(client, reg); + +	if (ret < 0) +		dev_err(&client->dev, "%s: err %d\n", __func__, ret); + +	return ret; +} + +static int fsa9480_read_irq(struct i2c_client *client, int *value) +{ +	int ret; + +	ret = i2c_smbus_read_i2c_block_data(client, +			FSA9480_REG_INT1, 2, (u8 *)value); +	*value &= 0xffff; + +	if (ret < 0) +		dev_err(&client->dev, "%s: err %d\n", __func__, ret); + +	return ret; +} + +static void fsa9480_set_switch(const char *buf) +{ +	struct fsa9480_usbsw *usbsw = chip; +	struct i2c_client *client = usbsw->client; +	unsigned int value; +	unsigned int path = 0; + +	value = fsa9480_read_reg(client, FSA9480_REG_CTRL); + +	if (!strncmp(buf, "VAUDIO", 6)) { +		path = SW_VAUDIO; +		value &= ~CON_MANUAL_SW; +	} else if (!strncmp(buf, "UART", 4)) { +		path = SW_UART; +		value &= ~CON_MANUAL_SW; +	} else if (!strncmp(buf, "AUDIO", 5)) { +		path = SW_AUDIO; +		value &= ~CON_MANUAL_SW; +	} else if (!strncmp(buf, "DHOST", 5)) { +		path = SW_DHOST; +		value &= ~CON_MANUAL_SW; +	} else if (!strncmp(buf, "AUTO", 4)) { +		path = SW_AUTO; +		value |= CON_MANUAL_SW; +	} else { +		printk(KERN_ERR "Wrong command\n"); +		return; +	} + +	usbsw->mansw = path; +	fsa9480_write_reg(client, FSA9480_REG_MANSW1, path); +	fsa9480_write_reg(client, FSA9480_REG_CTRL, value); +} + +static ssize_t fsa9480_get_switch(char *buf) +{ +	struct fsa9480_usbsw *usbsw = chip; +	struct i2c_client *client = usbsw->client; +	unsigned int value; + +	value = fsa9480_read_reg(client, FSA9480_REG_MANSW1); + +	if (value == SW_VAUDIO) +		return sprintf(buf, "VAUDIO\n"); +	else if (value == SW_UART) +		return sprintf(buf, "UART\n"); +	else if (value == SW_AUDIO) +		return sprintf(buf, "AUDIO\n"); +	else if (value == SW_DHOST) +		return sprintf(buf, "DHOST\n"); +	else if (value == SW_AUTO) +		return sprintf(buf, "AUTO\n"); +	else +		return sprintf(buf, "%x", value); +} + +static ssize_t fsa9480_show_device(struct device *dev, +				   struct device_attribute *attr, +				   char *buf) +{ +	struct fsa9480_usbsw *usbsw = dev_get_drvdata(dev); +	struct i2c_client *client = usbsw->client; +	int dev1, dev2; + +	dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1); +	dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2); + +	if (!dev1 && !dev2) +		return sprintf(buf, "NONE\n"); + +	/* USB */ +	if (dev1 & DEV_T1_USB_MASK || dev2 & DEV_T2_USB_MASK) +		return sprintf(buf, "USB\n"); + +	/* UART */ +	if (dev1 & DEV_T1_UART_MASK || dev2 & DEV_T2_UART_MASK) +		return sprintf(buf, "UART\n"); + +	/* CHARGER */ +	if (dev1 & DEV_T1_CHARGER_MASK) +		return sprintf(buf, "CHARGER\n"); + +	/* JIG */ +	if (dev2 & DEV_T2_JIG_MASK) +		return sprintf(buf, "JIG\n"); + +	return sprintf(buf, "UNKNOWN\n"); +} + +static ssize_t fsa9480_show_manualsw(struct device *dev, +		struct device_attribute *attr, char *buf) +{ +	return fsa9480_get_switch(buf); + +} + +static ssize_t fsa9480_set_manualsw(struct device *dev, +				    struct device_attribute *attr, +				    const char *buf, size_t count) +{ +	fsa9480_set_switch(buf); + +	return count; +} + +static DEVICE_ATTR(device, S_IRUGO, fsa9480_show_device, NULL); +static DEVICE_ATTR(switch, S_IRUGO | S_IWUSR, +		fsa9480_show_manualsw, fsa9480_set_manualsw); + +static struct attribute *fsa9480_attributes[] = { +	&dev_attr_device.attr, +	&dev_attr_switch.attr, +	NULL +}; + +static const struct attribute_group fsa9480_group = { +	.attrs = fsa9480_attributes, +}; + +static void fsa9480_detect_dev(struct fsa9480_usbsw *usbsw, int intr) +{ +	int val1, val2, ctrl; +	struct fsa9480_platform_data *pdata = usbsw->pdata; +	struct i2c_client *client = usbsw->client; + +	val1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1); +	val2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2); +	ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL); + +	dev_info(&client->dev, "intr: 0x%x, dev1: 0x%x, dev2: 0x%x\n", +			intr, val1, val2); + +	if (!intr) +		goto out; + +	if (intr & INT_ATTACH) {	/* Attached */ +		/* USB */ +		if (val1 & DEV_T1_USB_MASK || val2 & DEV_T2_USB_MASK) { +			if (pdata->usb_cb) +				pdata->usb_cb(FSA9480_ATTACHED); + +			if (usbsw->mansw) { +				fsa9480_write_reg(client, +					FSA9480_REG_MANSW1, usbsw->mansw); +			} +		} + +		/* UART */ +		if (val1 & DEV_T1_UART_MASK || val2 & DEV_T2_UART_MASK) { +			if (pdata->uart_cb) +				pdata->uart_cb(FSA9480_ATTACHED); + +			if (!(ctrl & CON_MANUAL_SW)) { +				fsa9480_write_reg(client, +					FSA9480_REG_MANSW1, SW_UART); +			} +		} + +		/* CHARGER */ +		if (val1 & DEV_T1_CHARGER_MASK) { +			if (pdata->charger_cb) +				pdata->charger_cb(FSA9480_ATTACHED); +		} + +		/* JIG */ +		if (val2 & DEV_T2_JIG_MASK) { +			if (pdata->jig_cb) +				pdata->jig_cb(FSA9480_ATTACHED); +		} +	} else if (intr & INT_DETACH) {	/* Detached */ +		/* USB */ +		if (usbsw->dev1 & DEV_T1_USB_MASK || +			usbsw->dev2 & DEV_T2_USB_MASK) { +			if (pdata->usb_cb) +				pdata->usb_cb(FSA9480_DETACHED); +		} + +		/* UART */ +		if (usbsw->dev1 & DEV_T1_UART_MASK || +			usbsw->dev2 & DEV_T2_UART_MASK) { +			if (pdata->uart_cb) +				pdata->uart_cb(FSA9480_DETACHED); +		} + +		/* CHARGER */ +		if (usbsw->dev1 & DEV_T1_CHARGER_MASK) { +			if (pdata->charger_cb) +				pdata->charger_cb(FSA9480_DETACHED); +		} + +		/* JIG */ +		if (usbsw->dev2 & DEV_T2_JIG_MASK) { +			if (pdata->jig_cb) +				pdata->jig_cb(FSA9480_DETACHED); +		} +	} + +	usbsw->dev1 = val1; +	usbsw->dev2 = val2; + +out: +	ctrl &= ~CON_INT_MASK; +	fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl); +} + +static irqreturn_t fsa9480_irq_handler(int irq, void *data) +{ +	struct fsa9480_usbsw *usbsw = data; +	struct i2c_client *client = usbsw->client; +	int intr; + +	/* clear interrupt */ +	fsa9480_read_irq(client, &intr); + +	/* device detection */ +	fsa9480_detect_dev(usbsw, intr); + +	return IRQ_HANDLED; +} + +static int fsa9480_irq_init(struct fsa9480_usbsw *usbsw) +{ +	struct fsa9480_platform_data *pdata = usbsw->pdata; +	struct i2c_client *client = usbsw->client; +	int ret; +	int intr; +	unsigned int ctrl = CON_MASK; + +	/* clear interrupt */ +	fsa9480_read_irq(client, &intr); + +	/* unmask interrupt (attach/detach only) */ +	fsa9480_write_reg(client, FSA9480_REG_INT1_MASK, 0xfc); +	fsa9480_write_reg(client, FSA9480_REG_INT2_MASK, 0x1f); + +	usbsw->mansw = fsa9480_read_reg(client, FSA9480_REG_MANSW1); + +	if (usbsw->mansw) +		ctrl &= ~CON_MANUAL_SW;	/* Manual Switching Mode */ + +	fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl); + +	if (pdata && pdata->cfg_gpio) +		pdata->cfg_gpio(); + +	if (client->irq) { +		ret = request_threaded_irq(client->irq, NULL, +				fsa9480_irq_handler, +				IRQF_TRIGGER_FALLING | IRQF_ONESHOT, +				"fsa9480 micro USB", usbsw); +		if (ret) { +			dev_err(&client->dev, "failed to reqeust IRQ\n"); +			return ret; +		} + +		device_init_wakeup(&client->dev, pdata->wakeup); +	} + +	return 0; +} + +static int __devinit fsa9480_probe(struct i2c_client *client, +			 const struct i2c_device_id *id) +{ +	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); +	struct fsa9480_usbsw *usbsw; +	int ret = 0; + +	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) +		return -EIO; + +	usbsw = kzalloc(sizeof(struct fsa9480_usbsw), GFP_KERNEL); +	if (!usbsw) { +		dev_err(&client->dev, "failed to allocate driver data\n"); +		return -ENOMEM; +	} + +	usbsw->client = client; +	usbsw->pdata = client->dev.platform_data; + +	chip = usbsw; + +	i2c_set_clientdata(client, usbsw); + +	ret = fsa9480_irq_init(usbsw); +	if (ret) +		goto fail1; + +	ret = sysfs_create_group(&client->dev.kobj, &fsa9480_group); +	if (ret) { +		dev_err(&client->dev, +				"failed to create fsa9480 attribute group\n"); +		goto fail2; +	} + +	/* ADC Detect Time: 500ms */ +	fsa9480_write_reg(client, FSA9480_REG_TIMING1, 0x6); + +	if (chip->pdata->reset_cb) +		chip->pdata->reset_cb(); + +	/* device detection */ +	fsa9480_detect_dev(usbsw, INT_ATTACH); + +	pm_runtime_set_active(&client->dev); + +	return 0; + +fail2: +	if (client->irq) +		free_irq(client->irq, NULL); +fail1: +	i2c_set_clientdata(client, NULL); +	kfree(usbsw); +	return ret; +} + +static int __devexit fsa9480_remove(struct i2c_client *client) +{ +	struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); +	if (client->irq) +		free_irq(client->irq, NULL); +	i2c_set_clientdata(client, NULL); + +	sysfs_remove_group(&client->dev.kobj, &fsa9480_group); +	device_init_wakeup(&client->dev, 0); +	kfree(usbsw); +	return 0; +} + +#ifdef CONFIG_PM + +static int fsa9480_suspend(struct i2c_client *client, pm_message_t state) +{ +	struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); +	struct fsa9480_platform_data *pdata = usbsw->pdata; + +	if (device_may_wakeup(&client->dev) && client->irq) +		enable_irq_wake(client->irq); + +	if (pdata->usb_power) +		pdata->usb_power(0); + +	return 0; +} + +static int fsa9480_resume(struct i2c_client *client) +{ +	struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); +	int dev1, dev2; + +	if (device_may_wakeup(&client->dev) && client->irq) +		disable_irq_wake(client->irq); + +	/* +	 * Clear Pending interrupt. Note that detect_dev does what +	 * the interrupt handler does. So, we don't miss pending and +	 * we reenable interrupt if there is one. +	 */ +	fsa9480_read_reg(client, FSA9480_REG_INT1); +	fsa9480_read_reg(client, FSA9480_REG_INT2); + +	dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1); +	dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2); + +	/* device detection */ +	fsa9480_detect_dev(usbsw, (dev1 || dev2) ? INT_ATTACH : INT_DETACH); + +	return 0; +} + +#else + +#define fsa9480_suspend NULL +#define fsa9480_resume NULL + +#endif /* CONFIG_PM */ + +static const struct i2c_device_id fsa9480_id[] = { +	{"fsa9480", 0}, +	{} +}; +MODULE_DEVICE_TABLE(i2c, fsa9480_id); + +static struct i2c_driver fsa9480_i2c_driver = { +	.driver = { +		.name = "fsa9480", +	}, +	.probe = fsa9480_probe, +	.remove = __devexit_p(fsa9480_remove), +	.resume = fsa9480_resume, +	.suspend = fsa9480_suspend, +	.id_table = fsa9480_id, +}; + +static int __init fsa9480_init(void) +{ +	return i2c_add_driver(&fsa9480_i2c_driver); +} +module_init(fsa9480_init); + +static void __exit fsa9480_exit(void) +{ +	i2c_del_driver(&fsa9480_i2c_driver); +} +module_exit(fsa9480_exit); + +MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>"); +MODULE_DESCRIPTION("FSA9480 USB Switch driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 668d41e594a9..df03dd3bd0e2 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -270,7 +270,7 @@ ioc4_variant(struct ioc4_driver_data *idd)  	return IOC4_VARIANT_PCI_RT;  } -static void __devinit +static void  ioc4_load_modules(struct work_struct *work)  {  	request_module("sgiioc4"); diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index 81d7fa4ec0db..150cd7061b80 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c @@ -120,6 +120,7 @@ static int recur_count = REC_NUM_DEFAULT;  static enum cname cpoint = CN_INVALID;  static enum ctype cptype = CT_NONE;  static int count = DEFAULT_COUNT; +static DEFINE_SPINLOCK(count_lock);  module_param(recur_count, int, 0644);  MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\ @@ -230,11 +231,14 @@ static const char *cp_name_to_str(enum cname name)  static int lkdtm_parse_commandline(void)  {  	int i; +	unsigned long flags;  	if (cpoint_count < 1 || recur_count < 1)  		return -EINVAL; +	spin_lock_irqsave(&count_lock, flags);  	count = cpoint_count; +	spin_unlock_irqrestore(&count_lock, flags);  	/* No special parameters */  	if (!cpoint_type && !cpoint_name) @@ -349,6 +353,9 @@ static void lkdtm_do_action(enum ctype which)  static void lkdtm_handler(void)  { +	unsigned long flags; + +	spin_lock_irqsave(&count_lock, flags);  	count--;  	printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n",  			cp_name_to_str(cpoint), cp_type_to_str(cptype), count); @@ -357,6 +364,7 @@ static void lkdtm_handler(void)  		lkdtm_do_action(cptype);  		count = cpoint_count;  	} +	spin_unlock_irqrestore(&count_lock, flags);  }  static int lkdtm_register_cpoint(enum cname which) diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index 5fe79df44838..0fd7e77bee29 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -686,6 +686,8 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev,  	}  	if (id->driver_data == 1) { /* EG20T PCH */ +		const char *board_name; +  		retval = sysfs_create_file(&pdev->dev.kobj,  					   &dev_attr_pch_mac.attr);  		if (retval) @@ -701,7 +703,8 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev,  					       CLKCFG_CANCLK_MASK);  		/* quirk for CM-iTC board */ -		if (strstr(dmi_get_system_info(DMI_BOARD_NAME), "CM-iTC")) +		board_name = dmi_get_system_info(DMI_BOARD_NAME); +		if (board_name && strstr(board_name, "CM-iTC"))  			pch_phub_read_modify_write_reg(chip,  						(unsigned int)CLKCFG_REG_OFFSET,  						CLKCFG_UART_48MHZ | CLKCFG_BAUDDIV | @@ -732,6 +735,8 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev,  		 * Device8(GbE)  		 */  		iowrite32(0x000a0000, chip->pch_phub_base_address + 0x14); +		/* set the interrupt delay value */ +		iowrite32(0x25, chip->pch_phub_base_address + 0x140);  		chip->pch_opt_rom_start_address =\  						 PCH_PHUB_ROM_START_ADDR_ML7223;  		chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223; @@ -749,8 +754,6 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev,  		 * Device6(SATA 2):f  		 */  		iowrite32(0x0000ffa0, chip->pch_phub_base_address + 0x14); -		/* set the interrupt delay value */ -		iowrite32(0x25, chip->pch_phub_base_address + 0x140);  		chip->pch_opt_rom_start_address =\  						 PCH_PHUB_ROM_START_ADDR_ML7223;  		chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223; diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index b05db55c8c8e..21b28fc6d912 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -26,7 +26,7 @@  #include <linux/sched.h>  #include <linux/mutex.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include <asm/io.h>  #define PHANTOM_VERSION		"n0.9.8" diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index bb6f9255c17c..8653bd0b1a33 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -146,45 +146,54 @@ static void pti_write_to_aperture(struct pti_masterchannel *mc,  /**   *  pti_control_frame_built_and_sent()- control frame build and send function.   * - *  @mc: The master / channel structure on which the function - *       built a control frame. + *  @mc:          The master / channel structure on which the function + *                built a control frame. + *  @thread_name: The thread name associated with the master / channel or + *                'NULL' if using the 'current' global variable.   *   *  To be able to post process the PTI contents on host side, a control frame   *  is added before sending any PTI content. So the host side knows on   *  each PTI frame the name of the thread using a dedicated master / channel. - *  The thread name is retrieved from the 'current' global variable. + *  The thread name is retrieved from 'current' global variable if 'thread_name' + *  is 'NULL', else it is retrieved from 'thread_name' parameter.   *  This function builds this frame and sends it to a master ID CONTROL_ID.   *  The overhead is only 32 bytes since the driver only writes to HW   *  in 32 byte chunks.   */ - -static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc) +static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc, +					     const char *thread_name)  {  	struct pti_masterchannel mccontrol = {.master = CONTROL_ID,  					      .channel = 0}; +	const char *thread_name_p;  	const char *control_format = "%3d %3d %s";  	u8 control_frame[CONTROL_FRAME_LEN]; -	/* -	 * Since we access the comm member in current's task_struct, -	 * we only need to be as large as what 'comm' in that -	 * structure is. -	 */ -	char comm[TASK_COMM_LEN]; +	if (!thread_name) { +		/* +		 * Since we access the comm member in current's task_struct, +		 * we only need to be as large as what 'comm' in that +		 * structure is. +		 */ +		char comm[TASK_COMM_LEN]; -	if (!in_interrupt()) -		get_task_comm(comm, current); -	else -		strncpy(comm, "Interrupt", TASK_COMM_LEN); +		if (!in_interrupt()) +			get_task_comm(comm, current); +		else +			strncpy(comm, "Interrupt", TASK_COMM_LEN); -	/* Absolutely ensure our buffer is zero terminated. */ -	comm[TASK_COMM_LEN-1] = 0; +		/* Absolutely ensure our buffer is zero terminated. */ +		comm[TASK_COMM_LEN-1] = 0; +		thread_name_p = comm; +	} else { +		thread_name_p = thread_name; +	}  	mccontrol.channel = pti_control_channel;  	pti_control_channel = (pti_control_channel + 1) & 0x7f;  	snprintf(control_frame, CONTROL_FRAME_LEN, control_format, mc->master, -		mc->channel, comm); +		mc->channel, thread_name_p);  	pti_write_to_aperture(&mccontrol, control_frame, strlen(control_frame));  } @@ -206,18 +215,20 @@ static void pti_write_full_frame_to_aperture(struct pti_masterchannel *mc,  						const unsigned char *buf,  						int len)  { -	pti_control_frame_built_and_sent(mc); +	pti_control_frame_built_and_sent(mc, NULL);  	pti_write_to_aperture(mc, (u8 *)buf, len);  }  /**   * get_id()- Allocate a master and channel ID.   * - * @id_array: an array of bits representing what channel - *            id's are allocated for writing. - * @max_ids:  The max amount of available write IDs to use. - * @base_id:  The starting SW channel ID, based on the Intel - *            PTI arch. + * @id_array:    an array of bits representing what channel + *               id's are allocated for writing. + * @max_ids:     The max amount of available write IDs to use. + * @base_id:     The starting SW channel ID, based on the Intel + *               PTI arch. + * @thread_name: The thread name associated with the master / channel or + *               'NULL' if using the 'current' global variable.   *   * Returns:   *	pti_masterchannel struct with master, channel ID address @@ -227,7 +238,10 @@ static void pti_write_full_frame_to_aperture(struct pti_masterchannel *mc,   * channel id. The bit is one if the id is taken and 0 if free. For   * every master there are 128 channel id's.   */ -static struct pti_masterchannel *get_id(u8 *id_array, int max_ids, int base_id) +static struct pti_masterchannel *get_id(u8 *id_array, +					int max_ids, +					int base_id, +					const char *thread_name)  {  	struct pti_masterchannel *mc;  	int i, j, mask; @@ -257,7 +271,7 @@ static struct pti_masterchannel *get_id(u8 *id_array, int max_ids, int base_id)  	mc->master  = base_id;  	mc->channel = ((i & 0xf)<<3) + j;  	/* write new master Id / channel Id allocation to channel control */ -	pti_control_frame_built_and_sent(mc); +	pti_control_frame_built_and_sent(mc, thread_name);  	return mc;  } @@ -273,18 +287,22 @@ static struct pti_masterchannel *get_id(u8 *id_array, int max_ids, int base_id)   *				a master, channel ID address   *				to write to PTI HW.   * - * @type: 0- request Application  master, channel aperture ID write address. - *        1- request OS master, channel aperture ID write - *           address. - *        2- request Modem master, channel aperture ID - *           write address. - *        Other values, error. + * @type:        0- request Application  master, channel aperture ID + *                  write address. + *               1- request OS master, channel aperture ID write + *                  address. + *               2- request Modem master, channel aperture ID + *                  write address. + *               Other values, error. + * @thread_name: The thread name associated with the master / channel or + *               'NULL' if using the 'current' global variable.   *   * Returns:   *	pti_masterchannel struct   *	0 for error   */ -struct pti_masterchannel *pti_request_masterchannel(u8 type) +struct pti_masterchannel *pti_request_masterchannel(u8 type, +						    const char *thread_name)  {  	struct pti_masterchannel *mc; @@ -293,15 +311,18 @@ struct pti_masterchannel *pti_request_masterchannel(u8 type)  	switch (type) {  	case 0: -		mc = get_id(drv_data->ia_app, MAX_APP_IDS, APP_BASE_ID); +		mc = get_id(drv_data->ia_app, MAX_APP_IDS, +			    APP_BASE_ID, thread_name);  		break;  	case 1: -		mc = get_id(drv_data->ia_os, MAX_OS_IDS, OS_BASE_ID); +		mc = get_id(drv_data->ia_os, MAX_OS_IDS, +			    OS_BASE_ID, thread_name);  		break;  	case 2: -		mc = get_id(drv_data->ia_modem, MAX_MODEM_IDS, MODEM_BASE_ID); +		mc = get_id(drv_data->ia_modem, MAX_MODEM_IDS, +			    MODEM_BASE_ID, thread_name);  		break;  	default:  		mc = NULL; @@ -317,7 +338,8 @@ EXPORT_SYMBOL_GPL(pti_request_masterchannel);   *				a master, channel ID address   *				used to write to PTI HW.   * - * @mc: master, channel apeture ID address to be released. + * @mc: master, channel apeture ID address to be released.  This + *      will de-allocate the structure via kfree().   */  void pti_release_masterchannel(struct pti_masterchannel *mc)  { @@ -444,9 +466,9 @@ static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp)  }  /** - * pti_tty_intstall()- Used to set up specific master-channels - *		       to tty ports for organizational purposes when - *		       tracing viewed from debuging tools. + * pti_tty_install()- Used to set up specific master-channels + *		      to tty ports for organizational purposes when + *		      tracing viewed from debuging tools.   *   * @driver: tty driver information.   * @tty: tty struct containing pti information. @@ -471,12 +493,14 @@ static int pti_tty_install(struct tty_driver *driver, struct tty_struct *tty)  			return -ENOMEM;  		if (idx == PTITTY_MINOR_START) -			pti_tty_data->mc = pti_request_masterchannel(0); +			pti_tty_data->mc = pti_request_masterchannel(0, NULL);  		else -			pti_tty_data->mc = pti_request_masterchannel(2); +			pti_tty_data->mc = pti_request_masterchannel(2, NULL); -		if (pti_tty_data->mc == NULL) +		if (pti_tty_data->mc == NULL) { +			kfree(pti_tty_data);  			return -ENXIO; +		}  		tty->driver_data = pti_tty_data;  	} @@ -495,7 +519,7 @@ static void pti_tty_cleanup(struct tty_struct *tty)  	if (pti_tty_data == NULL)  		return;  	pti_release_masterchannel(pti_tty_data->mc); -	kfree(tty->driver_data); +	kfree(pti_tty_data);  	tty->driver_data = NULL;  } @@ -560,7 +584,7 @@ static int pti_char_open(struct inode *inode, struct file *filp)  	 * before assigning the value to filp->private_data.  	 * Slightly easier to debug if this driver needs debugging.  	 */ -	mc = pti_request_masterchannel(0); +	mc = pti_request_masterchannel(0, NULL);  	if (mc == NULL)  		return -ENOMEM;  	filp->private_data = mc; @@ -581,7 +605,7 @@ static int pti_char_open(struct inode *inode, struct file *filp)  static int pti_char_release(struct inode *inode, struct file *filp)  {  	pti_release_masterchannel(filp->private_data); -	kfree(filp->private_data); +	filp->private_data = NULL;  	return 0;  } diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index ee5109a3cd98..42f067347bc7 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -495,14 +495,14 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)  		}  	} +	dev->stats.tx_packets++; +	dev->stats.tx_bytes += skb->len; +  	if (atomic_dec_return(&queued_msg->use_count) == 0) {  		dev_kfree_skb(skb);  		kfree(queued_msg);  	} -	dev->stats.tx_packets++; -	dev->stats.tx_bytes += skb->len; -  	return NETDEV_TX_OK;  } diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c index 7aded90f9daa..cfbddbef11de 100644 --- a/drivers/misc/spear13xx_pcie_gadget.c +++ b/drivers/misc/spear13xx_pcie_gadget.c @@ -845,7 +845,7 @@ err_iounmap:  err_iounmap_app:  	iounmap(config->va_app_base);  err_kzalloc: -	kfree(config); +	kfree(target);  err_rel_res:  	release_mem_region(res1->start, resource_size(res1));  err_rel_res0: diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index f91f82eabda7..54c91ffe4a91 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -605,7 +605,7 @@ long st_unregister(struct st_proto_s *proto)  	pr_debug("%s: %d ", __func__, proto->chnl_id);  	st_kim_ref(&st_gdata, 0); -	if (proto->chnl_id >= ST_MAX_CHANNELS) { +	if (!st_gdata || proto->chnl_id >= ST_MAX_CHANNELS) {  		pr_err(" chnl_id %d not supported", proto->chnl_id);  		return -EPROTONOSUPPORT;  	} diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 5da93ee6f6be..38fd2f04c07e 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -245,9 +245,9 @@ void skip_change_remote_baud(unsigned char **ptr, long *len)  		pr_err("invalid action after change remote baud command");  	} else {  		*ptr = *ptr + sizeof(struct bts_action) + -			((struct bts_action *)nxt_action)->size; +			((struct bts_action *)cur_action)->size;  		*len = *len - (sizeof(struct bts_action) + -				((struct bts_action *)nxt_action)->size); +				((struct bts_action *)cur_action)->size);  		/* warn user on not commenting these in firmware */  		pr_warn("skipping the wait event of change remote baud");  	} @@ -604,6 +604,10 @@ void st_kim_ref(struct st_data_s **core_data, int id)  	struct kim_data_s	*kim_gdata;  	/* get kim_gdata reference from platform device */  	pdev = st_get_plat_device(id); +	if (!pdev) { +		*core_data = NULL; +		return; +	}  	kim_gdata = dev_get_drvdata(&pdev->dev);  	*core_data = kim_gdata->core_data;  } diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 6df5a55da110..053d36caf955 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -45,7 +45,7 @@  MODULE_AUTHOR("VMware, Inc.");  MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); -MODULE_VERSION("1.2.1.2-k"); +MODULE_VERSION("1.2.1.3-k");  MODULE_ALIAS("dmi:*:svnVMware*:*");  MODULE_ALIAS("vmware_vmmemctl");  MODULE_LICENSE("GPL"); @@ -215,7 +215,6 @@ struct vmballoon {  };  static struct vmballoon balloon; -static struct workqueue_struct *vmballoon_wq;  /*   * Send "start" command to the host, communicating supported version @@ -674,7 +673,12 @@ static void vmballoon_work(struct work_struct *work)  			vmballoon_deflate(b);  	} -	queue_delayed_work(vmballoon_wq, dwork, round_jiffies_relative(HZ)); +	/* +	 * We are using a freezable workqueue so that balloon operations are +	 * stopped while the system transitions to/from sleep/hibernation. +	 */ +	queue_delayed_work(system_freezable_wq, +			   dwork, round_jiffies_relative(HZ));  }  /* @@ -785,12 +789,6 @@ static int __init vmballoon_init(void)  	if (x86_hyper != &x86_hyper_vmware)  		return -ENODEV; -	vmballoon_wq = create_freezable_workqueue("vmmemctl"); -	if (!vmballoon_wq) { -		pr_err("failed to create workqueue\n"); -		return -ENOMEM; -	} -  	INIT_LIST_HEAD(&balloon.pages);  	INIT_LIST_HEAD(&balloon.refused_pages); @@ -805,34 +803,27 @@ static int __init vmballoon_init(void)  	 */  	if (!vmballoon_send_start(&balloon)) {  		pr_err("failed to send start command to the host\n"); -		error = -EIO; -		goto fail; +		return -EIO;  	}  	if (!vmballoon_send_guest_id(&balloon)) {  		pr_err("failed to send guest ID to the host\n"); -		error = -EIO; -		goto fail; +		return -EIO;  	}  	error = vmballoon_debugfs_init(&balloon);  	if (error) -		goto fail; +		return error; -	queue_delayed_work(vmballoon_wq, &balloon.dwork, 0); +	queue_delayed_work(system_freezable_wq, &balloon.dwork, 0);  	return 0; - -fail: -	destroy_workqueue(vmballoon_wq); -	return error;  }  module_init(vmballoon_init);  static void __exit vmballoon_exit(void)  {  	cancel_delayed_work_sync(&balloon.dwork); -	destroy_workqueue(vmballoon_wq);  	vmballoon_debugfs_exit(&balloon); | 
