diff options
Diffstat (limited to 'drivers/misc')
32 files changed, 751 insertions, 146 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 5664696f2d3a..6a1a092db146 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -500,6 +500,14 @@ config USB_SWITCH_FSA9480 stereo and mono audio, video, microphone and UART data to use a common connector port. +config MAX8997_MUIC + tristate "MAX8997 MUIC Support" + depends on MFD_MAX8997 + help + If you say yes here you get support for the MUIC device of + Maxim MAX8997 PMIC. + The MAX8997 MUIC is a USB port accessory detector and switch. + 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 b26495a02554..3e1d80106f04 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -48,3 +48,4 @@ obj-y += lis3lv02d/ obj-y += carma/ obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ +obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c index 2208a9d52622..d7a9aa14e5d5 100644 --- a/drivers/misc/ab8500-pwm.c +++ b/drivers/misc/ab8500-pwm.c @@ -8,8 +8,8 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/pwm.h> -#include <linux/mfd/ab8500.h> #include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/module.h> /* diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c index a39e0555df63..83adab69bfd4 100644 --- a/drivers/misc/ad525x_dpot-i2c.c +++ b/drivers/misc/ad525x_dpot-i2c.c @@ -1,7 +1,7 @@ /* * Driver for the Analog Devices digital potentiometers (I2C bus) * - * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. + * Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc. * * Licensed under the GPL-2 or later. */ @@ -11,7 +11,6 @@ #include "ad525x_dpot.h" -/* ------------------------------------------------------------------------- */ /* I2C bus functions */ static int write_d8(void *client, u8 val) { @@ -60,18 +59,13 @@ static int __devinit ad_dpot_i2c_probe(struct i2c_client *client, .bops = &bops, }; - struct ad_dpot_id dpot_id = { - .name = (char *) &id->name, - .devid = id->driver_data, - }; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { dev_err(&client->dev, "SMBUS Word Data not Supported\n"); return -EIO; } - return ad_dpot_probe(&client->dev, &bdata, &dpot_id); + return ad_dpot_probe(&client->dev, &bdata, id->driver_data, id->name); } static int __devexit ad_dpot_i2c_remove(struct i2c_client *client) diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c index 7f9a55afe05d..822749e41fea 100644 --- a/drivers/misc/ad525x_dpot-spi.c +++ b/drivers/misc/ad525x_dpot-spi.c @@ -1,7 +1,7 @@ /* * Driver for the Analog Devices digital potentiometers (SPI bus) * - * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. + * Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc. * * Licensed under the GPL-2 or later. */ @@ -11,40 +11,6 @@ #include "ad525x_dpot.h" -static const struct ad_dpot_id ad_dpot_spi_devlist[] = { - {.name = "ad5160", .devid = AD5160_ID}, - {.name = "ad5161", .devid = AD5161_ID}, - {.name = "ad5162", .devid = AD5162_ID}, - {.name = "ad5165", .devid = AD5165_ID}, - {.name = "ad5200", .devid = AD5200_ID}, - {.name = "ad5201", .devid = AD5201_ID}, - {.name = "ad5203", .devid = AD5203_ID}, - {.name = "ad5204", .devid = AD5204_ID}, - {.name = "ad5206", .devid = AD5206_ID}, - {.name = "ad5207", .devid = AD5207_ID}, - {.name = "ad5231", .devid = AD5231_ID}, - {.name = "ad5232", .devid = AD5232_ID}, - {.name = "ad5233", .devid = AD5233_ID}, - {.name = "ad5235", .devid = AD5235_ID}, - {.name = "ad5260", .devid = AD5260_ID}, - {.name = "ad5262", .devid = AD5262_ID}, - {.name = "ad5263", .devid = AD5263_ID}, - {.name = "ad5290", .devid = AD5290_ID}, - {.name = "ad5291", .devid = AD5291_ID}, - {.name = "ad5292", .devid = AD5292_ID}, - {.name = "ad5293", .devid = AD5293_ID}, - {.name = "ad7376", .devid = AD7376_ID}, - {.name = "ad8400", .devid = AD8400_ID}, - {.name = "ad8402", .devid = AD8402_ID}, - {.name = "ad8403", .devid = AD8403_ID}, - {.name = "adn2850", .devid = ADN2850_ID}, - {.name = "ad5270", .devid = AD5270_ID}, - {.name = "ad5271", .devid = AD5271_ID}, - {} -}; - -/* ------------------------------------------------------------------------- */ - /* SPI bus functions */ static int write8(void *client, u8 val) { @@ -109,36 +75,16 @@ static const struct ad_dpot_bus_ops bops = { .write_r8d8 = write16, .write_r8d16 = write24, }; - -static const struct ad_dpot_id *dpot_match_id(const struct ad_dpot_id *id, - char *name) -{ - while (id->name && id->name[0]) { - if (strcmp(name, id->name) == 0) - return id; - id++; - } - return NULL; -} - static int __devinit ad_dpot_spi_probe(struct spi_device *spi) { - char *name = spi->dev.platform_data; - const struct ad_dpot_id *dpot_id; - struct ad_dpot_bus_data bdata = { .client = spi, .bops = &bops, }; - dpot_id = dpot_match_id(ad_dpot_spi_devlist, name); - - if (dpot_id == NULL) { - dev_err(&spi->dev, "%s not in supported device list", name); - return -ENODEV; - } - - return ad_dpot_probe(&spi->dev, &bdata, dpot_id); + return ad_dpot_probe(&spi->dev, &bdata, + spi_get_device_id(spi)->driver_data, + spi_get_device_id(spi)->name); } static int __devexit ad_dpot_spi_remove(struct spi_device *spi) @@ -146,14 +92,47 @@ static int __devexit ad_dpot_spi_remove(struct spi_device *spi) return ad_dpot_remove(&spi->dev); } +static const struct spi_device_id ad_dpot_spi_id[] = { + {"ad5160", AD5160_ID}, + {"ad5161", AD5161_ID}, + {"ad5162", AD5162_ID}, + {"ad5165", AD5165_ID}, + {"ad5200", AD5200_ID}, + {"ad5201", AD5201_ID}, + {"ad5203", AD5203_ID}, + {"ad5204", AD5204_ID}, + {"ad5206", AD5206_ID}, + {"ad5207", AD5207_ID}, + {"ad5231", AD5231_ID}, + {"ad5232", AD5232_ID}, + {"ad5233", AD5233_ID}, + {"ad5235", AD5235_ID}, + {"ad5260", AD5260_ID}, + {"ad5262", AD5262_ID}, + {"ad5263", AD5263_ID}, + {"ad5290", AD5290_ID}, + {"ad5291", AD5291_ID}, + {"ad5292", AD5292_ID}, + {"ad5293", AD5293_ID}, + {"ad7376", AD7376_ID}, + {"ad8400", AD8400_ID}, + {"ad8402", AD8402_ID}, + {"ad8403", AD8403_ID}, + {"adn2850", ADN2850_ID}, + {"ad5270", AD5270_ID}, + {"ad5271", AD5271_ID}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad_dpot_spi_id); + static struct spi_driver ad_dpot_spi_driver = { .driver = { .name = "ad_dpot", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ad_dpot_spi_probe, .remove = __devexit_p(ad_dpot_spi_remove), + .id_table = ad_dpot_spi_id, }; static int __init ad_dpot_spi_init(void) diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index 7cb911028d09..1d1d42615915 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -64,7 +64,7 @@ * Author: Chris Verges <chrisv@cyberswitching.com> * * derived from ad5252.c - * Copyright (c) 2006 Michael Hennerich <hennerich@blackfin.uclinux.org> + * Copyright (c) 2006-2011 Michael Hennerich <hennerich@blackfin.uclinux.org> * * Licensed under the GPL-2 or later. */ @@ -76,8 +76,6 @@ #include <linux/delay.h> #include <linux/slab.h> -#define DRIVER_VERSION "0.2" - #include "ad525x_dpot.h" /* @@ -687,8 +685,9 @@ inline void ad_dpot_remove_files(struct device *dev, } } -__devinit int ad_dpot_probe(struct device *dev, - struct ad_dpot_bus_data *bdata, const struct ad_dpot_id *id) +int __devinit ad_dpot_probe(struct device *dev, + struct ad_dpot_bus_data *bdata, unsigned long devid, + const char *name) { struct dpot_data *data; @@ -704,13 +703,13 @@ __devinit int ad_dpot_probe(struct device *dev, mutex_init(&data->update_lock); data->bdata = *bdata; - data->devid = id->devid; + data->devid = devid; - data->max_pos = 1 << DPOT_MAX_POS(data->devid); + data->max_pos = 1 << DPOT_MAX_POS(devid); data->rdac_mask = data->max_pos - 1; - data->feat = DPOT_FEAT(data->devid); - data->uid = DPOT_UID(data->devid); - data->wipers = DPOT_WIPERS(data->devid); + data->feat = DPOT_FEAT(devid); + data->uid = DPOT_UID(devid); + data->wipers = DPOT_WIPERS(devid); for (i = DPOT_RDAC0; i < MAX_RDACS; i++) if (data->wipers & (1 << i)) { @@ -731,7 +730,7 @@ __devinit int ad_dpot_probe(struct device *dev, } dev_info(dev, "%s %d-Position Digital Potentiometer registered\n", - id->name, data->max_pos); + name, data->max_pos); return 0; @@ -745,7 +744,7 @@ exit_free: dev_set_drvdata(dev, NULL); exit: dev_err(dev, "failed to create client for %s ID 0x%lX\n", - id->name, id->devid); + name, devid); return err; } EXPORT_SYMBOL(ad_dpot_probe); @@ -770,4 +769,3 @@ MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, " "Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Digital potentiometer driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/misc/ad525x_dpot.h b/drivers/misc/ad525x_dpot.h index 82b2cb77ae19..6bd1eba23bc0 100644 --- a/drivers/misc/ad525x_dpot.h +++ b/drivers/misc/ad525x_dpot.h @@ -208,12 +208,8 @@ struct ad_dpot_bus_data { const struct ad_dpot_bus_ops *bops; }; -struct ad_dpot_id { - char *name; - unsigned long devid; -}; - -int ad_dpot_probe(struct device *dev, struct ad_dpot_bus_data *bdata, const struct ad_dpot_id *id); +int ad_dpot_probe(struct device *dev, struct ad_dpot_bus_data *bdata, + unsigned long devid, const char *name); int ad_dpot_remove(struct device *dev); #endif diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c index 5f898cb706a6..b29a2be24591 100644 --- a/drivers/misc/bmp085.c +++ b/drivers/misc/bmp085.c @@ -216,7 +216,7 @@ static s32 bmp085_get_temperature(struct bmp085_data *data, int *temperature) *temperature = (x1+x2+8) >> 4; exit: - return status;; + return status; } /* diff --git a/drivers/misc/carma/carma-fpga-program.c b/drivers/misc/carma/carma-fpga-program.c index eb5cd28bc6d8..a2d25e4857e3 100644 --- a/drivers/misc/carma/carma-fpga-program.c +++ b/drivers/misc/carma/carma-fpga-program.c @@ -513,7 +513,7 @@ static noinline int fpga_program_dma(struct fpga_dev *priv) * transaction, and then put it under external control */ memset(&config, 0, sizeof(config)); - config.direction = DMA_TO_DEVICE; + config.direction = DMA_MEM_TO_DEV; config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; config.dst_maxburst = fpga_fifo_size(priv->regs) / 2 / 4; ret = chan->device->device_control(chan, DMA_SLAVE_CONFIG, diff --git a/drivers/misc/eeprom/eeprom_93cx6.c b/drivers/misc/eeprom/eeprom_93cx6.c index 7b33de95c4bf..0ff4b02177be 100644 --- a/drivers/misc/eeprom/eeprom_93cx6.c +++ b/drivers/misc/eeprom/eeprom_93cx6.c @@ -63,6 +63,7 @@ static void eeprom_93cx6_startup(struct eeprom_93cx6 *eeprom) eeprom->reg_data_out = 0; eeprom->reg_data_clock = 0; eeprom->reg_chip_select = 1; + eeprom->drive_data = 1; eeprom->register_write(eeprom); /* @@ -101,6 +102,7 @@ static void eeprom_93cx6_write_bits(struct eeprom_93cx6 *eeprom, */ eeprom->reg_data_in = 0; eeprom->reg_data_out = 0; + eeprom->drive_data = 1; /* * Start writing all bits. @@ -140,6 +142,7 @@ static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom, */ eeprom->reg_data_in = 0; eeprom->reg_data_out = 0; + eeprom->drive_data = 0; /* * Start reading all bits. @@ -231,3 +234,88 @@ void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word, } EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread); +/** + * eeprom_93cx6_wren - set the write enable state + * @eeprom: Pointer to eeprom structure + * @enable: true to enable writes, otherwise disable writes + * + * Set the EEPROM write enable state to either allow or deny + * writes depending on the @enable value. + */ +void eeprom_93cx6_wren(struct eeprom_93cx6 *eeprom, bool enable) +{ + u16 command; + + /* start the command */ + eeprom_93cx6_startup(eeprom); + + /* create command to enable/disable */ + + command = enable ? PCI_EEPROM_EWEN_OPCODE : PCI_EEPROM_EWDS_OPCODE; + command <<= (eeprom->width - 2); + + eeprom_93cx6_write_bits(eeprom, command, + PCI_EEPROM_WIDTH_OPCODE + eeprom->width); + + eeprom_93cx6_cleanup(eeprom); +} +EXPORT_SYMBOL_GPL(eeprom_93cx6_wren); + +/** + * eeprom_93cx6_write - write data to the EEPROM + * @eeprom: Pointer to eeprom structure + * @addr: Address to write data to. + * @data: The data to write to address @addr. + * + * Write the @data to the specified @addr in the EEPROM and + * waiting for the device to finish writing. + * + * Note, since we do not expect large number of write operations + * we delay in between parts of the operation to avoid using excessive + * amounts of CPU time busy waiting. + */ +void eeprom_93cx6_write(struct eeprom_93cx6 *eeprom, u8 addr, u16 data) +{ + int timeout = 100; + u16 command; + + /* start the command */ + eeprom_93cx6_startup(eeprom); + + command = PCI_EEPROM_WRITE_OPCODE << eeprom->width; + command |= addr; + + /* send write command */ + eeprom_93cx6_write_bits(eeprom, command, + PCI_EEPROM_WIDTH_OPCODE + eeprom->width); + + /* send data */ + eeprom_93cx6_write_bits(eeprom, data, 16); + + /* get ready to check for busy */ + eeprom->drive_data = 0; + eeprom->reg_chip_select = 1; + eeprom->register_write(eeprom); + + /* wait at-least 250ns to get DO to be the busy signal */ + usleep_range(1000, 2000); + + /* wait for DO to go high to signify finish */ + + while (true) { + eeprom->register_read(eeprom); + + if (eeprom->reg_data_out) + break; + + usleep_range(1000, 2000); + + if (--timeout <= 0) { + printk(KERN_ERR "%s: timeout\n", __func__); + break; + } + } + + eeprom_93cx6_cleanup(eeprom); +} +EXPORT_SYMBOL_GPL(eeprom_93cx6_write); diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c index 5c766b4fb238..7d56f45dee19 100644 --- a/drivers/misc/ibmasm/command.c +++ b/drivers/misc/ibmasm/command.c @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * */ diff --git a/drivers/misc/ibmasm/dot_command.c b/drivers/misc/ibmasm/dot_command.c index 3dd2dfb8da17..d7b2ca358b23 100644 --- a/drivers/misc/ibmasm/dot_command.c +++ b/drivers/misc/ibmasm/dot_command.c @@ -17,7 +17,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * */ diff --git a/drivers/misc/ibmasm/dot_command.h b/drivers/misc/ibmasm/dot_command.h index 6cbba1afef35..fc9fc9d4e087 100644 --- a/drivers/misc/ibmasm/dot_command.h +++ b/drivers/misc/ibmasm/dot_command.h @@ -17,7 +17,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * */ diff --git a/drivers/misc/ibmasm/event.c b/drivers/misc/ibmasm/event.c index 76bfda1ffaa9..8e540f4e9d52 100644 --- a/drivers/misc/ibmasm/event.c +++ b/drivers/misc/ibmasm/event.c @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * */ diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c index 1bc4306572a4..90746378f9b7 100644 --- a/drivers/misc/ibmasm/heartbeat.c +++ b/drivers/misc/ibmasm/heartbeat.c @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * */ diff --git a/drivers/misc/ibmasm/i2o.h b/drivers/misc/ibmasm/i2o.h index bf2c738d2b72..2e9566dab2b1 100644 --- a/drivers/misc/ibmasm/i2o.h +++ b/drivers/misc/ibmasm/i2o.h @@ -17,7 +17,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * */ diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h index 4d8a4e248b34..9b083448814d 100644 --- a/drivers/misc/ibmasm/ibmasm.h +++ b/drivers/misc/ibmasm/ibmasm.h @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * */ diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 89947723a27d..35361753b487 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -17,7 +17,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * */ diff --git a/drivers/misc/ibmasm/lowlevel.c b/drivers/misc/ibmasm/lowlevel.c index 4b2398e27fd5..5319ea261c05 100644 --- a/drivers/misc/ibmasm/lowlevel.c +++ b/drivers/misc/ibmasm/lowlevel.c @@ -17,7 +17,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * */ diff --git a/drivers/misc/ibmasm/lowlevel.h b/drivers/misc/ibmasm/lowlevel.h index 766766523a60..e97848f51b3f 100644 --- a/drivers/misc/ibmasm/lowlevel.h +++ b/drivers/misc/ibmasm/lowlevel.h @@ -17,7 +17,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * */ diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index a234d965243b..1ccedb71e728 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * * This driver is based on code originally written by Pete Reynolds * and others. diff --git a/drivers/misc/ibmasm/r_heartbeat.c b/drivers/misc/ibmasm/r_heartbeat.c index 2de487ac788c..232034f5da48 100644 --- a/drivers/misc/ibmasm/r_heartbeat.c +++ b/drivers/misc/ibmasm/r_heartbeat.c @@ -16,7 +16,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * */ diff --git a/drivers/misc/ibmasm/remote.h b/drivers/misc/ibmasm/remote.h index 00dbf1d4373a..a7729ef76acb 100644 --- a/drivers/misc/ibmasm/remote.h +++ b/drivers/misc/ibmasm/remote.h @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * * Originally written by Pete Reynolds */ diff --git a/drivers/misc/ibmasm/uart.c b/drivers/misc/ibmasm/uart.c index 93baa350d698..1dcb9ae1905a 100644 --- a/drivers/misc/ibmasm/uart.c +++ b/drivers/misc/ibmasm/uart.c @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck <amax@us.ibm.com> + * Author: Max Asböck <amax@us.ibm.com> * */ diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c index 307aada5fffe..3d6cce663bea 100644 --- a/drivers/misc/isl29020.c +++ b/drivers/misc/isl29020.c @@ -158,7 +158,7 @@ static int als_set_default_config(struct i2c_client *client) dev_err(&client->dev, "default write failed."); return retval; } - return 0;; + return 0; } static int isl29020_probe(struct i2c_client *client, diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c index b1f4563be9ae..701eb600b127 100644 --- a/drivers/misc/iwmc3200top/main.c +++ b/drivers/misc/iwmc3200top/main.c @@ -376,20 +376,20 @@ static int blocks; module_param(blocks, int, 0604); MODULE_PARM_DESC(blocks, "max_blocks_to_send"); -static int dump; +static bool dump; module_param(dump, bool, 0604); MODULE_PARM_DESC(dump, "dump_hex_content"); -static int jump = 1; +static bool jump = 1; module_param(jump, bool, 0604); -static int direct = 1; +static bool direct = 1; module_param(direct, bool, 0604); -static int checksum = 1; +static bool checksum = 1; module_param(checksum, bool, 0604); -static int fw_download = 1; +static bool fw_download = 1; module_param(fw_download, bool, 0604); static int block_size = IWMC_SDIO_BLK_SIZE; @@ -398,7 +398,7 @@ module_param(block_size, int, 0404); static int download_trans_blks = IWMC_DEFAULT_TR_BLK; module_param(download_trans_blks, int, 0604); -static int rubbish_barker; +static bool rubbish_barker; module_param(rubbish_barker, bool, 0604); #ifdef CONFIG_IWMC3200TOP_DEBUG diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index 29d12a70eb1b..a981e2a42f92 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -111,6 +111,8 @@ static struct kernel_param_ops param_ops_axis = { .get = param_get_int, }; +#define param_check_axis(name, p) param_check_int(name, p) + module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644); MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions"); diff --git a/drivers/misc/max8997-muic.c b/drivers/misc/max8997-muic.c new file mode 100644 index 000000000000..d74ef41aabd5 --- /dev/null +++ b/drivers/misc/max8997-muic.c @@ -0,0 +1,505 @@ +/* + * max8997-muic.c - MAX8997 muic driver for the Maxim 8997 + * + * Copyright (C) 2011 Samsung Electrnoics + * Donggeun Kim <dg77.kim@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/kobject.h> +#include <linux/mfd/max8997.h> +#include <linux/mfd/max8997-private.h> + +/* MAX8997-MUIC STATUS1 register */ +#define STATUS1_ADC_SHIFT 0 +#define STATUS1_ADCLOW_SHIFT 5 +#define STATUS1_ADCERR_SHIFT 6 +#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT) +#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT) +#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT) + +/* MAX8997-MUIC STATUS2 register */ +#define STATUS2_CHGTYP_SHIFT 0 +#define STATUS2_CHGDETRUN_SHIFT 3 +#define STATUS2_DCDTMR_SHIFT 4 +#define STATUS2_DBCHG_SHIFT 5 +#define STATUS2_VBVOLT_SHIFT 6 +#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT) +#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT) +#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT) +#define STATUS2_DBCHG_MASK (0x1 << STATUS2_DBCHG_SHIFT) +#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT) + +/* MAX8997-MUIC STATUS3 register */ +#define STATUS3_OVP_SHIFT 2 +#define STATUS3_OVP_MASK (0x1 << STATUS3_OVP_SHIFT) + +/* MAX8997-MUIC CONTROL1 register */ +#define COMN1SW_SHIFT 0 +#define COMP2SW_SHIFT 3 +#define COMN1SW_MASK (0x7 << COMN1SW_SHIFT) +#define COMP2SW_MASK (0x7 << COMP2SW_SHIFT) +#define SW_MASK (COMP2SW_MASK | COMN1SW_MASK) + +#define MAX8997_SW_USB ((1 << COMP2SW_SHIFT) | (1 << COMN1SW_SHIFT)) +#define MAX8997_SW_AUDIO ((2 << COMP2SW_SHIFT) | (2 << COMN1SW_SHIFT)) +#define MAX8997_SW_UART ((3 << COMP2SW_SHIFT) | (3 << COMN1SW_SHIFT)) +#define MAX8997_SW_OPEN ((0 << COMP2SW_SHIFT) | (0 << COMN1SW_SHIFT)) + +#define MAX8997_ADC_GROUND 0x00 +#define MAX8997_ADC_MHL 0x01 +#define MAX8997_ADC_JIG_USB_1 0x18 +#define MAX8997_ADC_JIG_USB_2 0x19 +#define MAX8997_ADC_DESKDOCK 0x1a +#define MAX8997_ADC_JIG_UART 0x1c +#define MAX8997_ADC_CARDOCK 0x1d +#define MAX8997_ADC_OPEN 0x1f + +struct max8997_muic_irq { + unsigned int irq; + const char *name; +}; + +static struct max8997_muic_irq muic_irqs[] = { + { MAX8997_MUICIRQ_ADCError, "muic-ADC_error" }, + { MAX8997_MUICIRQ_ADCLow, "muic-ADC_low" }, + { MAX8997_MUICIRQ_ADC, "muic-ADC" }, + { MAX8997_MUICIRQ_VBVolt, "muic-VB_voltage" }, + { MAX8997_MUICIRQ_DBChg, "muic-DB_charger" }, + { MAX8997_MUICIRQ_DCDTmr, "muic-DCD_timer" }, + { MAX8997_MUICIRQ_ChgDetRun, "muic-CDR_status" }, + { MAX8997_MUICIRQ_ChgTyp, "muic-charger_type" }, + { MAX8997_MUICIRQ_OVP, "muic-over_voltage" }, +}; + +struct max8997_muic_info { + struct device *dev; + struct max8997_dev *iodev; + struct i2c_client *muic; + struct max8997_muic_platform_data *muic_pdata; + + int irq; + struct work_struct irq_work; + + enum max8997_muic_charger_type pre_charger_type; + int pre_adc; + + struct mutex mutex; +}; + +static int max8997_muic_handle_usb(struct max8997_muic_info *info, + enum max8997_muic_usb_type usb_type, bool attached) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + int ret = 0; + + if (usb_type == MAX8997_USB_HOST) { + /* switch to USB */ + ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, + attached ? MAX8997_SW_USB : MAX8997_SW_OPEN, + SW_MASK); + if (ret) { + dev_err(info->dev, "failed to update muic register\n"); + goto out; + } + } + + if (mdata->usb_callback) + mdata->usb_callback(usb_type, attached); +out: + return ret; +} + +static void max8997_muic_handle_mhl(struct max8997_muic_info *info, + bool attached) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + + if (mdata->mhl_callback) + mdata->mhl_callback(attached); +} + +static int max8997_muic_handle_dock(struct max8997_muic_info *info, + int adc, bool attached) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + int ret = 0; + + /* switch to AUDIO */ + ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, + attached ? MAX8997_SW_AUDIO : MAX8997_SW_OPEN, + SW_MASK); + if (ret) { + dev_err(info->dev, "failed to update muic register\n"); + goto out; + } + + switch (adc) { + case MAX8997_ADC_DESKDOCK: + if (mdata->deskdock_callback) + mdata->deskdock_callback(attached); + break; + case MAX8997_ADC_CARDOCK: + if (mdata->cardock_callback) + mdata->cardock_callback(attached); + break; + default: + break; + } +out: + return ret; +} + +static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, + bool attached) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + int ret = 0; + + /* switch to UART */ + ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, + attached ? MAX8997_SW_UART : MAX8997_SW_OPEN, + SW_MASK); + if (ret) { + dev_err(info->dev, "failed to update muic register\n"); + goto out; + } + + if (mdata->uart_callback) + mdata->uart_callback(attached); +out: + return ret; +} + +static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info) +{ + int ret = 0; + + switch (info->pre_adc) { + case MAX8997_ADC_GROUND: + ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false); + break; + case MAX8997_ADC_MHL: + max8997_muic_handle_mhl(info, false); + break; + case MAX8997_ADC_JIG_USB_1: + case MAX8997_ADC_JIG_USB_2: + ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, false); + break; + case MAX8997_ADC_DESKDOCK: + case MAX8997_ADC_CARDOCK: + ret = max8997_muic_handle_dock(info, info->pre_adc, false); + break; + case MAX8997_ADC_JIG_UART: + ret = max8997_muic_handle_jig_uart(info, false); + break; + default: + break; + } + + return ret; +} + +static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc) +{ + int ret = 0; + + switch (adc) { + case MAX8997_ADC_GROUND: + ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true); + break; + case MAX8997_ADC_MHL: + max8997_muic_handle_mhl(info, true); + break; + case MAX8997_ADC_JIG_USB_1: + case MAX8997_ADC_JIG_USB_2: + ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true); + break; + case MAX8997_ADC_DESKDOCK: + case MAX8997_ADC_CARDOCK: + ret = max8997_muic_handle_dock(info, adc, true); + break; + case MAX8997_ADC_JIG_UART: + ret = max8997_muic_handle_jig_uart(info, true); + break; + case MAX8997_ADC_OPEN: + ret = max8997_muic_handle_adc_detach(info); + break; + default: + break; + } + + info->pre_adc = adc; + + return ret; +} + +static int max8997_muic_handle_charger_type(struct max8997_muic_info *info, + enum max8997_muic_charger_type charger_type) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + u8 adc; + int ret; + + ret = max8997_read_reg(info->muic, MAX8997_MUIC_REG_STATUS1, &adc); + if (ret) { + dev_err(info->dev, "failed to read muic register\n"); + goto out; + } + + switch (charger_type) { + case MAX8997_CHARGER_TYPE_NONE: + if (mdata->charger_callback) + mdata->charger_callback(false, charger_type); + if (info->pre_charger_type == MAX8997_CHARGER_TYPE_USB) { + max8997_muic_handle_usb(info, + MAX8997_USB_DEVICE, false); + } + break; + case MAX8997_CHARGER_TYPE_USB: + if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) { + max8997_muic_handle_usb(info, + MAX8997_USB_DEVICE, true); + } + if (mdata->charger_callback) + mdata->charger_callback(true, charger_type); + break; + case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: + case MAX8997_CHARGER_TYPE_DEDICATED_CHG: + case MAX8997_CHARGER_TYPE_500MA: + case MAX8997_CHARGER_TYPE_1A: + if (mdata->charger_callback) + mdata->charger_callback(true, charger_type); + break; + default: + break; + } + + info->pre_charger_type = charger_type; +out: + return ret; +} + +static void max8997_muic_irq_work(struct work_struct *work) +{ + struct max8997_muic_info *info = container_of(work, + struct max8997_muic_info, irq_work); + struct max8997_platform_data *pdata = + dev_get_platdata(info->iodev->dev); + u8 status[3]; + u8 adc, chg_type; + + int irq_type = info->irq - pdata->irq_base; + int ret; + + mutex_lock(&info->mutex); + + ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, + 3, status); + if (ret) { + dev_err(info->dev, "failed to read muic register\n"); + mutex_unlock(&info->mutex); + return; + } + + dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__, + status[0], status[1]); + + switch (irq_type) { + case MAX8997_MUICIRQ_ADC: + adc = status[0] & STATUS1_ADC_MASK; + adc >>= STATUS1_ADC_SHIFT; + + max8997_muic_handle_adc(info, adc); + break; + case MAX8997_MUICIRQ_ChgTyp: + chg_type = status[1] & STATUS2_CHGTYP_MASK; + chg_type >>= STATUS2_CHGTYP_SHIFT; + + max8997_muic_handle_charger_type(info, chg_type); + break; + default: + dev_info(info->dev, "misc interrupt: %s occurred\n", + muic_irqs[irq_type].name); + break; + } + + mutex_unlock(&info->mutex); + + return; +} + +static irqreturn_t max8997_muic_irq_handler(int irq, void *data) +{ + struct max8997_muic_info *info = data; + + dev_dbg(info->dev, "irq:%d\n", irq); + info->irq = irq; + + schedule_work(&info->irq_work); + + return IRQ_HANDLED; +} + +static void max8997_muic_detect_dev(struct max8997_muic_info *info) +{ + int ret; + u8 status[2], adc, chg_type; + + ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, + 2, status); + if (ret) { + dev_err(info->dev, "failed to read muic register\n"); + return; + } + + dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n", + status[0], status[1]); + + adc = status[0] & STATUS1_ADC_MASK; + adc >>= STATUS1_ADC_SHIFT; + + chg_type = status[1] & STATUS2_CHGTYP_MASK; + chg_type >>= STATUS2_CHGTYP_SHIFT; + + max8997_muic_handle_adc(info, adc); + max8997_muic_handle_charger_type(info, chg_type); +} + +static void max8997_initialize_device(struct max8997_muic_info *info) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + int i; + + for (i = 0; i < mdata->num_init_data; i++) { + max8997_write_reg(info->muic, mdata->init_data[i].addr, + mdata->init_data[i].data); + } +} + +static int __devinit max8997_muic_probe(struct platform_device *pdev) +{ + struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); + struct max8997_muic_info *info; + int ret, i; + + info = kzalloc(sizeof(struct max8997_muic_info), GFP_KERNEL); + if (!info) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + ret = -ENOMEM; + goto err_kfree; + } + + if (!pdata->muic_pdata) { + dev_err(&pdev->dev, "failed to get platform_data\n"); + ret = -EINVAL; + goto err_pdata; + } + info->muic_pdata = pdata->muic_pdata; + + info->dev = &pdev->dev; + info->iodev = iodev; + info->muic = iodev->muic; + + platform_set_drvdata(pdev, info); + mutex_init(&info->mutex); + + INIT_WORK(&info->irq_work, max8997_muic_irq_work); + + for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) { + struct max8997_muic_irq *muic_irq = &muic_irqs[i]; + + ret = request_threaded_irq(pdata->irq_base + muic_irq->irq, + NULL, max8997_muic_irq_handler, + 0, muic_irq->name, + info); + if (ret) { + dev_err(&pdev->dev, + "failed: irq request (IRQ: %d," + " error :%d)\n", + muic_irq->irq, ret); + + for (i = i - 1; i >= 0; i--) + free_irq(muic_irq->irq, info); + + goto err_irq; + } + } + + /* Initialize registers according to platform data */ + max8997_initialize_device(info); + + /* Initial device detection */ + max8997_muic_detect_dev(info); + + return ret; + +err_irq: +err_pdata: + kfree(info); +err_kfree: + return ret; +} + +static int __devexit max8997_muic_remove(struct platform_device *pdev) +{ + struct max8997_muic_info *info = platform_get_drvdata(pdev); + struct max8997_platform_data *pdata = + dev_get_platdata(info->iodev->dev); + int i; + + for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) + free_irq(pdata->irq_base + muic_irqs[i].irq, info); + cancel_work_sync(&info->irq_work); + + kfree(info); + + return 0; +} + +static struct platform_driver max8997_muic_driver = { + .driver = { + .name = "max8997-muic", + .owner = THIS_MODULE, + }, + .probe = max8997_muic_probe, + .remove = __devexit_p(max8997_muic_remove), +}; + +static int __init max8997_muic_init(void) +{ + return platform_driver_register(&max8997_muic_driver); +} +module_init(max8997_muic_init); + +static void __exit max8997_muic_exit(void) +{ + platform_driver_unregister(&max8997_muic_driver); +} +module_exit(max8997_muic_exit); + +MODULE_DESCRIPTION("Maxim MAX8997 MUIC driver"); +MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/sgi-gru/gruprocfs.c b/drivers/misc/sgi-gru/gruprocfs.c index 7768b87d995b..950dbe9ecb36 100644 --- a/drivers/misc/sgi-gru/gruprocfs.c +++ b/drivers/misc/sgi-gru/gruprocfs.c @@ -324,7 +324,7 @@ static const struct file_operations gru_fops = { static struct proc_entry { char *name; - int mode; + umode_t mode; const struct file_operations *fops; struct proc_dir_entry *entry; } proc_files[] = { diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 42f067347bc7..3fac67a5204c 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -576,7 +576,7 @@ xpnet_init(void) * report an error if the data is not retrievable and the * packet will be dropped. */ - xpnet_device->features = NETIF_F_NO_CSUM; + xpnet_device->features = NETIF_F_HW_CSUM; result = register_netdev(xpnet_device); if (result != 0) { diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index ba168a7d54d4..2b62232c2c6a 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -137,6 +137,8 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) * st_reg_complete - * to call registration complete callbacks * of all protocol stack drivers + * This function is being called with spin lock held, protocol drivers are + * only expected to complete their waits and do nothing more than that. */ void st_reg_complete(struct st_data_s *st_gdata, char err) { @@ -538,11 +540,12 @@ long st_register(struct st_proto_s *new_proto) set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); st_recv = st_kim_recv; + /* enable the ST LL - to set default chip state */ + st_ll_enable(st_gdata); + /* release lock previously held - re-locked below */ spin_unlock_irqrestore(&st_gdata->lock, flags); - /* enable the ST LL - to set default chip state */ - st_ll_enable(st_gdata); /* this may take a while to complete * since it involves BT fw download */ @@ -553,10 +556,13 @@ long st_register(struct st_proto_s *new_proto) (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { pr_err(" KIM failure complete callback "); st_reg_complete(st_gdata, err); + clear_bit(ST_REG_PENDING, &st_gdata->st_state); } return -EINVAL; } + spin_lock_irqsave(&st_gdata->lock, flags); + clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); st_recv = st_int_recv; @@ -576,10 +582,10 @@ long st_register(struct st_proto_s *new_proto) if (st_gdata->is_registered[new_proto->chnl_id] == true) { pr_err(" proto %d already registered ", new_proto->chnl_id); + spin_unlock_irqrestore(&st_gdata->lock, flags); return -EALREADY; } - spin_lock_irqsave(&st_gdata->lock, flags); add_channel_to_table(st_gdata, new_proto); st_gdata->protos_registered++; new_proto->write = st_write; @@ -619,7 +625,7 @@ long st_unregister(struct st_proto_s *proto) spin_lock_irqsave(&st_gdata->lock, flags); - if (st_gdata->list[proto->chnl_id] == NULL) { + if (st_gdata->is_registered[proto->chnl_id] == false) { pr_err(" chnl_id %d not registered", proto->chnl_id); spin_unlock_irqrestore(&st_gdata->lock, flags); return -EPROTONOSUPPORT; @@ -629,6 +635,10 @@ long st_unregister(struct st_proto_s *proto) remove_channel_from_table(st_gdata, proto); spin_unlock_irqrestore(&st_gdata->lock, flags); + /* paranoid check */ + if (st_gdata->protos_registered < ST_EMPTY) + st_gdata->protos_registered = ST_EMPTY; + if ((st_gdata->protos_registered == ST_EMPTY) && (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { pr_info(" all chnl_ids unregistered "); diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 43ef8d162f2d..a7a861ceee2d 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -469,37 +469,21 @@ long st_kim_start(void *kim_data) /* wait for ldisc to be installed */ err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME)); - if (!err) { /* timeout */ - pr_err("line disc installation timed out "); - kim_gdata->ldisc_install = 0; - pr_info("ldisc_install = 0"); - sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, - NULL, "install"); - /* the following wait is never going to be completed, - * since the ldisc was never installed, hence serving - * as a mdelay of LDISC_TIME msecs */ - err = wait_for_completion_timeout - (&kim_gdata->ldisc_installed, - msecs_to_jiffies(LDISC_TIME)); - err = -ETIMEDOUT; + if (!err) { + /* ldisc installation timeout, + * flush uart, power cycle BT_EN */ + pr_err("ldisc installation timeout"); + err = st_kim_stop(kim_gdata); continue; } else { /* ldisc installed now */ - pr_info(" line discipline installed "); + pr_info("line discipline installed"); err = download_firmware(kim_gdata); if (err != 0) { + /* ldisc installed but fw download failed, + * flush uart & power cycle BT_EN */ pr_err("download firmware failed"); - kim_gdata->ldisc_install = 0; - pr_info("ldisc_install = 0"); - sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, - NULL, "install"); - /* this wait might be completed, though in the - * tty_close() since the ldisc is already - * installed */ - err = wait_for_completion_timeout - (&kim_gdata->ldisc_installed, - msecs_to_jiffies(LDISC_TIME)); - err = -EINVAL; + err = st_kim_stop(kim_gdata); continue; } else { /* on success don't retry */ break; @@ -510,8 +494,14 @@ long st_kim_start(void *kim_data) } /** - * st_kim_stop - called from ST Core, on the last un-registration - * toggle low the chip enable gpio + * st_kim_stop - stop communication with chip. + * This can be called from ST Core/KIM, on the- + * (a) last un-register when chip need not be powered there-after, + * (b) upon failure to either install ldisc or download firmware. + * The function is responsible to (a) notify UIM about un-installation, + * (b) flush UART if the ldisc was installed. + * (c) reset BT_EN - pull down nshutdown at the end. + * (d) invoke platform's chip disabling routine. */ long st_kim_stop(void *kim_data) { @@ -519,12 +509,16 @@ long st_kim_stop(void *kim_data) struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; struct ti_st_plat_data *pdata = kim_gdata->kim_pdev->dev.platform_data; + struct tty_struct *tty = kim_gdata->core_data->tty; INIT_COMPLETION(kim_gdata->ldisc_installed); - /* Flush any pending characters in the driver and discipline. */ - tty_ldisc_flush(kim_gdata->core_data->tty); - tty_driver_flush_buffer(kim_gdata->core_data->tty); + if (tty) { /* can be called before ldisc is installed */ + /* Flush any pending characters in the driver and discipline. */ + tty_ldisc_flush(tty); + tty_driver_flush_buffer(tty); + tty->ops->flush_buffer(tty); + } /* send uninstall notification to UIM */ pr_info("ldisc_install = 0"); @@ -579,6 +573,28 @@ static ssize_t show_install(struct device *dev, return sprintf(buf, "%d\n", kim_data->ldisc_install); } +#ifdef DEBUG +static ssize_t store_dev_name(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct kim_data_s *kim_data = dev_get_drvdata(dev); + pr_debug("storing dev name >%s<", buf); + strncpy(kim_data->dev_name, buf, count); + pr_debug("stored dev name >%s<", kim_data->dev_name); + return count; +} + +static ssize_t store_baud_rate(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct kim_data_s *kim_data = dev_get_drvdata(dev); + pr_debug("storing baud rate >%s<", buf); + sscanf(buf, "%ld", &kim_data->baud_rate); + pr_debug("stored baud rate >%ld<", kim_data->baud_rate); + return count; +} +#endif /* if DEBUG */ + static ssize_t show_dev_name(struct device *dev, struct device_attribute *attr, char *buf) { @@ -605,10 +621,18 @@ static struct kobj_attribute ldisc_install = __ATTR(install, 0444, (void *)show_install, NULL); static struct kobj_attribute uart_dev_name = +#ifdef DEBUG /* TODO: move this to debug-fs if possible */ +__ATTR(dev_name, 0644, (void *)show_dev_name, (void *)store_dev_name); +#else __ATTR(dev_name, 0444, (void *)show_dev_name, NULL); +#endif static struct kobj_attribute uart_baud_rate = +#ifdef DEBUG /* TODO: move to debugfs */ +__ATTR(baud_rate, 0644, (void *)show_baud_rate, (void *)store_baud_rate); +#else __ATTR(baud_rate, 0444, (void *)show_baud_rate, NULL); +#endif static struct kobj_attribute uart_flow_cntrl = __ATTR(flow_cntrl, 0444, (void *)show_flow_cntrl, NULL); |