Skip to content

Commit

Permalink
Merge tag 'char-misc-3.9-rc4' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/gregkh/char-misc

Pull char/misc driver fixes from Greg Kroah-Hartman:
 "Here are some small char/misc driver fixes that resolve issues
  recently reported against the 3.9-rc kernels.  All have been in
  linux-next for a while."

* tag 'char-misc-3.9-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc:
  VMCI: Fix process-to-process DRGAMs.
  mei: ME hardware reset needs to be synchronized
  mei: add mei_stop function to stop mei device
  extcon: max77693: Initialize register of MUIC device to bring up it without platform data
  extcon: max77693: Fix bug of wrong pointer when platform data is not used
  extcon: max8997: Check the pointer of platform data to protect null pointer error
  • Loading branch information
Linus Torvalds committed Mar 28, 2013
2 parents dfca53f + 347e089 commit 1b6a4db
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 100 deletions.
103 changes: 80 additions & 23 deletions drivers/extcon/extcon-max77693.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,38 @@
#define DEV_NAME "max77693-muic"
#define DELAY_MS_DEFAULT 20000 /* unit: millisecond */

/*
* Default value of MAX77693 register to bring up MUIC device.
* If user don't set some initial value for MUIC device through platform data,
* extcon-max77693 driver use 'default_init_data' to bring up base operation
* of MAX77693 MUIC device.
*/
struct max77693_reg_data default_init_data[] = {
{
/* STATUS2 - [3]ChgDetRun */
.addr = MAX77693_MUIC_REG_STATUS2,
.data = STATUS2_CHGDETRUN_MASK,
}, {
/* INTMASK1 - Unmask [3]ADC1KM,[0]ADCM */
.addr = MAX77693_MUIC_REG_INTMASK1,
.data = INTMASK1_ADC1K_MASK
| INTMASK1_ADC_MASK,
}, {
/* INTMASK2 - Unmask [0]ChgTypM */
.addr = MAX77693_MUIC_REG_INTMASK2,
.data = INTMASK2_CHGTYP_MASK,
}, {
/* INTMASK3 - Mask all of interrupts */
.addr = MAX77693_MUIC_REG_INTMASK3,
.data = 0x0,
}, {
/* CDETCTRL2 */
.addr = MAX77693_MUIC_REG_CDETCTRL2,
.data = CDETCTRL2_VIDRMEN_MASK
| CDETCTRL2_DXOVPEN_MASK,
},
};

enum max77693_muic_adc_debounce_time {
ADC_DEBOUNCE_TIME_5MS = 0,
ADC_DEBOUNCE_TIME_10MS,
Expand Down Expand Up @@ -1045,8 +1077,9 @@ static int max77693_muic_probe(struct platform_device *pdev)
{
struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev);
struct max77693_muic_platform_data *muic_pdata = pdata->muic_data;
struct max77693_muic_info *info;
struct max77693_reg_data *init_data;
int num_init_data;
int delay_jiffies;
int ret;
int i;
Expand Down Expand Up @@ -1145,15 +1178,25 @@ static int max77693_muic_probe(struct platform_device *pdev)
goto err_irq;
}

/* Initialize MUIC register by using platform data */
for (i = 0 ; i < muic_pdata->num_init_data ; i++) {
enum max77693_irq_source irq_src = MAX77693_IRQ_GROUP_NR;

/* Initialize MUIC register by using platform data or default data */
if (pdata->muic_data) {
init_data = pdata->muic_data->init_data;
num_init_data = pdata->muic_data->num_init_data;
} else {
init_data = default_init_data;
num_init_data = ARRAY_SIZE(default_init_data);
}

for (i = 0 ; i < num_init_data ; i++) {
enum max77693_irq_source irq_src
= MAX77693_IRQ_GROUP_NR;

max77693_write_reg(info->max77693->regmap_muic,
muic_pdata->init_data[i].addr,
muic_pdata->init_data[i].data);
init_data[i].addr,
init_data[i].data);

switch (muic_pdata->init_data[i].addr) {
switch (init_data[i].addr) {
case MAX77693_MUIC_REG_INTMASK1:
irq_src = MUIC_INT1;
break;
Expand All @@ -1167,22 +1210,40 @@ static int max77693_muic_probe(struct platform_device *pdev)

if (irq_src < MAX77693_IRQ_GROUP_NR)
info->max77693->irq_masks_cur[irq_src]
= muic_pdata->init_data[i].data;
= init_data[i].data;
}

/*
* Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
* h/w path of COMP2/COMN1 on CONTROL1 register.
*/
if (muic_pdata->path_uart)
info->path_uart = muic_pdata->path_uart;
else
info->path_uart = CONTROL1_SW_UART;
if (pdata->muic_data) {
struct max77693_muic_platform_data *muic_pdata = pdata->muic_data;

if (muic_pdata->path_usb)
info->path_usb = muic_pdata->path_usb;
else
/*
* Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
* h/w path of COMP2/COMN1 on CONTROL1 register.
*/
if (muic_pdata->path_uart)
info->path_uart = muic_pdata->path_uart;
else
info->path_uart = CONTROL1_SW_UART;

if (muic_pdata->path_usb)
info->path_usb = muic_pdata->path_usb;
else
info->path_usb = CONTROL1_SW_USB;

/*
* Default delay time for detecting cable state
* after certain time.
*/
if (muic_pdata->detcable_delay_ms)
delay_jiffies =
msecs_to_jiffies(muic_pdata->detcable_delay_ms);
else
delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
} else {
info->path_usb = CONTROL1_SW_USB;
info->path_uart = CONTROL1_SW_UART;
delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
}

/* Set initial path for UART */
max77693_muic_set_path(info, info->path_uart, true);
Expand All @@ -1208,10 +1269,6 @@ static int max77693_muic_probe(struct platform_device *pdev)
* driver should notify cable state to upper layer.
*/
INIT_DELAYED_WORK(&info->wq_detcable, max77693_muic_detect_cable_wq);
if (muic_pdata->detcable_delay_ms)
delay_jiffies = msecs_to_jiffies(muic_pdata->detcable_delay_ms);
else
delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
schedule_delayed_work(&info->wq_detcable, delay_jiffies);

return ret;
Expand Down
56 changes: 34 additions & 22 deletions drivers/extcon/extcon-max8997.c
Original file line number Diff line number Diff line change
Expand Up @@ -712,29 +712,45 @@ static int max8997_muic_probe(struct platform_device *pdev)
goto err_irq;
}

/* Initialize registers according to platform data */
if (pdata->muic_pdata) {
struct max8997_muic_platform_data *mdata = info->muic_pdata;

for (i = 0; i < mdata->num_init_data; i++) {
max8997_write_reg(info->muic, mdata->init_data[i].addr,
mdata->init_data[i].data);
struct max8997_muic_platform_data *muic_pdata
= pdata->muic_pdata;

/* Initialize registers according to platform data */
for (i = 0; i < muic_pdata->num_init_data; i++) {
max8997_write_reg(info->muic,
muic_pdata->init_data[i].addr,
muic_pdata->init_data[i].data);
}
}

/*
* Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
* h/w path of COMP2/COMN1 on CONTROL1 register.
*/
if (pdata->muic_pdata->path_uart)
info->path_uart = pdata->muic_pdata->path_uart;
else
info->path_uart = CONTROL1_SW_UART;
/*
* Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
* h/w path of COMP2/COMN1 on CONTROL1 register.
*/
if (muic_pdata->path_uart)
info->path_uart = muic_pdata->path_uart;
else
info->path_uart = CONTROL1_SW_UART;

if (pdata->muic_pdata->path_usb)
info->path_usb = pdata->muic_pdata->path_usb;
else
if (muic_pdata->path_usb)
info->path_usb = muic_pdata->path_usb;
else
info->path_usb = CONTROL1_SW_USB;

/*
* Default delay time for detecting cable state
* after certain time.
*/
if (muic_pdata->detcable_delay_ms)
delay_jiffies =
msecs_to_jiffies(muic_pdata->detcable_delay_ms);
else
delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
} else {
info->path_uart = CONTROL1_SW_UART;
info->path_usb = CONTROL1_SW_USB;
delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
}

/* Set initial path for UART */
max8997_muic_set_path(info, info->path_uart, true);
Expand All @@ -751,10 +767,6 @@ static int max8997_muic_probe(struct platform_device *pdev)
* driver should notify cable state to upper layer.
*/
INIT_DELAYED_WORK(&info->wq_detcable, max8997_muic_detect_cable_wq);
if (pdata->muic_pdata->detcable_delay_ms)
delay_jiffies = msecs_to_jiffies(pdata->muic_pdata->detcable_delay_ms);
else
delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
schedule_delayed_work(&info->wq_detcable, delay_jiffies);

return 0;
Expand Down
29 changes: 20 additions & 9 deletions drivers/misc/mei/hw-me.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,20 @@ static void mei_me_intr_disable(struct mei_device *dev)
mei_hcsr_set(hw, hcsr);
}

/**
* mei_me_hw_reset_release - release device from the reset
*
* @dev: the device structure
*/
static void mei_me_hw_reset_release(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);

hcsr |= H_IG;
hcsr &= ~H_RST;
mei_hcsr_set(hw, hcsr);
}
/**
* mei_me_hw_reset - resets fw via mei csr register.
*
Expand All @@ -169,18 +183,14 @@ static void mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
if (intr_enable)
hcsr |= H_IE;
else
hcsr &= ~H_IE;

mei_hcsr_set(hw, hcsr);

hcsr = mei_hcsr_read(hw) | H_IG;
hcsr &= ~H_RST;
hcsr |= ~H_IE;

mei_hcsr_set(hw, hcsr);

hcsr = mei_hcsr_read(hw);
if (dev->dev_state == MEI_DEV_POWER_DOWN)
mei_me_hw_reset_release(dev);

dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", hcsr);
dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", mei_hcsr_read(hw));
}

/**
Expand Down Expand Up @@ -466,7 +476,8 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
mutex_unlock(&dev->device_lock);
return IRQ_HANDLED;
} else {
dev_dbg(&dev->pdev->dev, "FW not ready.\n");
dev_dbg(&dev->pdev->dev, "Reset Completed.\n");
mei_me_hw_reset_release(dev);
mutex_unlock(&dev->device_lock);
return IRQ_HANDLED;
}
Expand Down
18 changes: 18 additions & 0 deletions drivers/misc/mei/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,24 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
mei_cl_all_write_clear(dev);
}

void mei_stop(struct mei_device *dev)
{
dev_dbg(&dev->pdev->dev, "stopping the device.\n");

mutex_lock(&dev->device_lock);

cancel_delayed_work(&dev->timer_work);

mei_wd_stop(dev);

dev->dev_state = MEI_DEV_POWER_DOWN;
mei_reset(dev, 0);

mutex_unlock(&dev->device_lock);

flush_scheduled_work();
}




1 change: 1 addition & 0 deletions drivers/misc/mei/mei_dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ static inline unsigned long mei_secs_to_jiffies(unsigned long sec)
void mei_device_init(struct mei_device *dev);
void mei_reset(struct mei_device *dev, int interrupts);
int mei_hw_init(struct mei_device *dev);
void mei_stop(struct mei_device *dev);

/*
* MEI interrupt functions prototype
Expand Down
52 changes: 7 additions & 45 deletions drivers/misc/mei/pci-me.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,44 +247,14 @@ static void mei_remove(struct pci_dev *pdev)

hw = to_me_hw(dev);

mutex_lock(&dev->device_lock);

cancel_delayed_work(&dev->timer_work);

mei_wd_stop(dev);
dev_err(&pdev->dev, "stop\n");
mei_stop(dev);

mei_pdev = NULL;

if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
mei_cl_disconnect(&dev->iamthif_cl);
}
if (dev->wd_cl.state == MEI_FILE_CONNECTED) {
dev->wd_cl.state = MEI_FILE_DISCONNECTING;
mei_cl_disconnect(&dev->wd_cl);
}

/* Unregistering watchdog device */
mei_watchdog_unregister(dev);

/* remove entry if already in list */
dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");

if (dev->open_handle_count > 0)
dev->open_handle_count--;
mei_cl_unlink(&dev->wd_cl);

if (dev->open_handle_count > 0)
dev->open_handle_count--;
mei_cl_unlink(&dev->iamthif_cl);

dev->iamthif_current_cb = NULL;
dev->me_clients_num = 0;

mutex_unlock(&dev->device_lock);

flush_scheduled_work();

/* disable interrupts */
mei_disable_interrupts(dev);

Expand All @@ -308,28 +278,20 @@ static int mei_pci_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct mei_device *dev = pci_get_drvdata(pdev);
int err;

if (!dev)
return -ENODEV;
mutex_lock(&dev->device_lock);

cancel_delayed_work(&dev->timer_work);
dev_err(&pdev->dev, "suspend\n");

/* Stop watchdog if exists */
err = mei_wd_stop(dev);
/* Set new mei state */
if (dev->dev_state == MEI_DEV_ENABLED ||
dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
dev->dev_state = MEI_DEV_POWER_DOWN;
mei_reset(dev, 0);
}
mutex_unlock(&dev->device_lock);
mei_stop(dev);

mei_disable_interrupts(dev);

free_irq(pdev->irq, dev);
pci_disable_msi(pdev);

return err;
return 0;
}

static int mei_pci_resume(struct device *device)
Expand Down
Loading

0 comments on commit 1b6a4db

Please sign in to comment.