diff options
| -rw-r--r-- | arch/arm/boot/dts/omap3_h1.dts | 29 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/board-omap3h1.c | 9 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 2 | ||||
| -rw-r--r-- | drivers/power/bq27x00_battery.c | 218 | ||||
| -rw-r--r-- | drivers/staging/triune/ts81001.c | 272 | ||||
| -rw-r--r-- | drivers/staging/triune/ts81001.h | 4 | ||||
| -rw-r--r-- | sound/soc/codecs/Kconfig | 4 | ||||
| -rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
| -rw-r--r-- | sound/soc/codecs/omap3h1_bt_sco.c | 74 | ||||
| -rw-r--r-- | sound/soc/omap/Kconfig | 1 | ||||
| -rw-r--r-- | sound/soc/omap/omap3h1.c | 197 | 
11 files changed, 665 insertions, 147 deletions
| diff --git a/arch/arm/boot/dts/omap3_h1.dts b/arch/arm/boot/dts/omap3_h1.dts index 7b922bb66b0..46c6e2d97b1 100644 --- a/arch/arm/boot/dts/omap3_h1.dts +++ b/arch/arm/boot/dts/omap3_h1.dts @@ -68,7 +68,7 @@  		 * for a gpio IRQ (banks numbered 1 to 6)  		 *   irq = 16 + 96 + (gpio_bank - 1) * 32 + GPIO no.  		 */ -        compatible = "ti,pad-wkup"; +		compatible = "ti,pad-wkup";  		/* Map the pad offset (off) to an interrupt (IRQ).    */  		/* if handle is 1, an irq will be generated based on  */ @@ -83,15 +83,16 @@  		/*             off  IRQ handle                        */  		ti,pad_irq = <0x150  88  1>, /* 72 + 16, uart1 - BT input      */ -                     <0x9f6  143 1>, /* mpu6515 irq pin - is this offset correct?      */ -                     <0x9ea  122 1>, /* bq27400 chg irq8 */ -                     <0x9f4  123 1>, /* BT host wake          */ -                     <0x1b0  23  1>; /* sys_nirq              */ +			<0x9f6  143 1>, /* mpu6515 irq pin - is this offset correct?      */ +			/* <0x9ea  122 1>, */ /* bq27400 chg irq8 - needed here? */ +			<0x9f4  123 1>, /* BT host wake          */ +			<0x1b0  23  1>; /* sys_nirq              */  	};  	sound {  		compatible = "olio,omap-soc-omap3h1"; -		olio,mcbsp = <&mcbsp3>; +		olio,mcbsp_bt = <&mcbsp2>; +		olio,mcbsp_mic = <&mcbsp3>;  		olio,mic_enable = <&gpio5 18 0>;  	};  }; @@ -215,14 +216,14 @@  	    >;  	}; -    dev_pins: pinmux_pv_pins { -      pinctrl-single,pins = < -          0x5b2 0x204      /* USB control, ETK_D3, MODE4 | OUTPUT */ -          /* 0x1a2 0x104 */      /* ALS interrupt, input, GPIO */ -          0x086 0x004  /* DRV2605 vibrator, output, GPIO */ -          /* 0x938 0x104 */  /* Battery state, input, GPIO */ -          >; -    }; +dev_pins: pinmux_pv_pins { +		pinctrl-single,pins = < +			0x5b2 0x204      /* USB control, ETK_D3, MODE4 | OUTPUT */ +			/* 0x1a2 0x104 */      /* ALS interrupt, input, GPIO */ +			0x086 0x004  /* DRV2605 vibrator, output, GPIO */ +			/* 0x938 0x104 */  /* Battery state, input, GPIO */ +			>; +	};  	/*  	i2c1_pins: pinmux_i2c1_pins { diff --git a/arch/arm/mach-omap2/board-omap3h1.c b/arch/arm/mach-omap2/board-omap3h1.c index ad40bd6d90e..7915962e45b 100644 --- a/arch/arm/mach-omap2/board-omap3h1.c +++ b/arch/arm/mach-omap2/board-omap3h1.c @@ -254,6 +254,10 @@ static struct platform_device omap3h1_dmic_codec = {  	.id = -1,  }; +static struct platform_device omap3h1_bt_codec = { +		.name = "omap3h1_bt_sco", +		.id = -1, +};  /* --------------------------------------------------------------------------- */  /* USB settings  @@ -473,9 +477,10 @@ static int __init omap3_h1_i2c_init(void)  static struct platform_device *omap3h1_devices[] __initdata = { -	&bcm20702_bluetooth_device, -	&nop_phy_device, +        &bcm20702_bluetooth_device, +        &nop_phy_device,  	&omap3h1_dmic_codec, +	&omap3h1_bt_codec,  };  static void __init omap3_h1_init(void) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0e15ad357aa..00fb5ac811c 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -690,7 +690,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)  	r = omap_i2c_wait_for_bb(dev);  	/* If timeout, try to again check after attempting to clear the bus */ -	if (WARN_ON(r == -ETIMEDOUT)) { +	if (r == -ETIMEDOUT) {  /* removed WARN_ON here, too much output from ts81001 */  		r = omap_i2c_bus_clear(dev);  		if (r < 0) {  			dev_err(dev->dev, "Unable to recover i2c bus from bb\n"); diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index c26859a2f84..8002531960e 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -47,18 +47,30 @@  #include <linux/power/bq27x00_battery.h>  #ifdef CONFIG_OLIO_TS81001 + +/*  + * OLIO Model One needs the fuel gauge to talk to the charger in some + * instances, such as deciding whether we're using the wireless  + * charger or not. Hence this build flag. + *  + * In hindsight, a lot of this can probably be moved to the charger  + * manager. + */ +#include <linux/alarmtimer.h> +#include "asm/io.h" +#include "../../arch/arm/mach-omap2/mux.h" +#include "../../arch/arm/mach-omap2/iomap.h"  #include "../staging/triune/ts81001.h"  #endif /* CONFIG_OLIO_TS81001 */ -  #ifdef OLIODEBUG -#define do { olio_debug(format, ...) printk("OLIO %s: ", __FUNCTION__);	\ +#define olio_debug(format, ...) do { \ +		printk("OLIO %s: ", __FUNCTION__);		\  		printk(format, ##__VA_ARGS__); } while(0)  #else  #define olio_debug(format, ...)   #endif -  #define DRIVER_VERSION			"1.2.0"  #define INVALID_REG_ADDR		0xFF @@ -84,8 +96,14 @@ enum bq27xxx_reg_index {  	NUM_REGS  }; +/* lock taken if we want the upper layers to run */  +  struct wake_lock chg_wake_lock; +/* lock taken by interrupt to let work queue run*/ + +struct wake_lock isr_wake_lock; +  /* bq27500 registers */  static __initdata u8 bq27500_regs[NUM_REGS] = {  	0x00,	/* CONTROL	*/ @@ -226,7 +244,7 @@ static __initdata u8 bq276xx_regs[NUM_REGS] = {  #define BQ274XX_UNSEAL_KEY		0x80008000  #define BQ274XX_SOFT_RESET		0x43 -#define BQ274XX_FLAG_ITPOR				0x20 +#define BQ274XX_FLAG_ITPOR		0x20  #define BQ274XX_CTRL_STATUS_INITCOMP	0x80  #define BQ27XXX_FLAG_DSC		BIT(0) @@ -261,6 +279,8 @@ static __initdata u8 bq276xx_regs[NUM_REGS] = {  #define BQ276XX_OP_CFG_B_OFFSET		2  #define BQ276XX_OP_CFG_B_DEF_SEAL_BIT	(1 << 5) +#define BQ27X00_ALARM_TIMER_INTERVAL    300 /* 5 minutes */ +  struct bq27x00_device_info;  struct bq27x00_access_methods {  	int (*read)(struct bq27x00_device_info *di, u8 reg, bool single); @@ -306,6 +326,7 @@ struct bq27x00_device_info {  	unsigned long last_update;  	struct delayed_work work; +	struct delayed_work interrupt_work;  	struct power_supply	bat; @@ -318,6 +339,9 @@ struct bq27x00_device_info {  	u8 regs[NUM_REGS];  	struct dm_reg *dm_regs;  	u16 dm_regs_count; + +	struct alarm poll_alarm; +	ktime_t alarm_time;  };  static __initdata enum power_supply_property bq27x00_battery_props[] = { @@ -410,6 +434,9 @@ static __initdata enum power_supply_property bq276xx_battery_props[] = {   * Ordering the parameters based on subclass and then offset will help in   * having fewer flash writes while updating.   * Customize these values and, if necessary, add more based on system needs. + + To be added, maybe (for bq274xx): + {81, 9, 1, 3},	         Quit Relax Time (3s)   */  static struct dm_reg bq274xx_dm_regs[] = {  	{36, 6, 1, 90}, 	/* FC Clear % */ @@ -438,6 +465,8 @@ module_param(poll_interval, uint, 0644);  MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \  				"0 disables polling"); +static volatile int mA_now; +  /*   * Forward Declarations   */ @@ -445,6 +474,14 @@ static int read_dm_block(struct bq27x00_device_info *di, u8 subclass,  	u8 offset, u8 *data); +#ifdef CONFIG_OLIO_TS81001 +static int bq27x00_charger_status(struct bq27x00_device_info *di,  +				  union power_supply_propval *val); +static int bq27x00_battery_status(struct bq27x00_device_info *di, +				  union power_supply_propval *val); +#endif + +  /*   * Common code for BQ27x00 devices   */ @@ -974,7 +1011,12 @@ static void bq27x00_update(struct bq27x00_device_info *di)  	bool is_bq274xx = di->chip == BQ274XX;  	bool is_bq276xx = di->chip == BQ276XX; +	olio_debug ("entered\n"); +  	cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, !is_bq27500); + +	olio_debug ("Cache flags read from bq is 0x%x\n", cache.flags); +  	if (cache.flags >= 0) {  		if (is_bq27200 && (cache.flags & BQ27200_FLAG_CI)) {  			dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n"); @@ -1060,10 +1102,11 @@ static bool rom_mode_gauge_dm_initialized(struct bq27x00_device_info *di)  	dev_dbg(di->dev, "%s: flags - 0x%04x\n", __func__, flags); -	if (flags & BQ274XX_FLAG_ITPOR) +	if (flags & BQ274XX_FLAG_ITPOR) {  		return false; -	else +	} else {  		return true; +	}  }  #define INITCOMP_TIMEOUT_MS		10000 @@ -1103,6 +1146,9 @@ static void rom_mode_gauge_dm_init(struct bq27x00_device_info *di)  		subclass = dm_reg->subclass;  		offset = dm_reg->offset; +		olio_debug ("updating reg %d, offset %d\n",   +			subclass, offset); +  		/*  		 * Create a composite block number to see if the subsequent  		 * register also belongs to the same 32 btye block in the DM @@ -1136,10 +1182,40 @@ static void rom_mode_gauge_dm_init(struct bq27x00_device_info *di)  	exit_cfg_update_mode(di);  } -static void bq27x00_battery_poll(struct work_struct *work) + +/*************************************************************************** + * bq27x00_battery_interrupt - work to do from interrupt + * + * Decide whether we actually want to wake up, then take a wake lock if  + * appropriate. + */ + +static void bq27x00_battery_interrupt (struct work_struct *i_work)   { +	int status; +	union power_supply_propval val;  	struct bq27x00_device_info *di = -		container_of(work, struct bq27x00_device_info, work.work); +		container_of(i_work, struct bq27x00_device_info, interrupt_work.work); + +	olio_debug ("taking charge wake lock\n"); + +	wake_lock_timeout(&chg_wake_lock, msecs_to_jiffies(500));	 +	bq27x00_update (di); +	status = bq27x00_battery_status(di, &val); + +	olio_debug ("battery status = %d\n", status); + +	/* release the low-level wake lock (taken in isr handler) */ +	wake_unlock (&isr_wake_lock); +} + + +static void bq27x00_battery_poll(struct work_struct *p_work) +{ +	struct bq27x00_device_info *di = +		container_of(p_work, struct bq27x00_device_info, work.work); + +	olio_debug ("entered\n");  	if (((di->chip == BQ274XX) || (di->chip == BQ276XX)) &&  		!rom_mode_gauge_dm_initialized(di)) { @@ -1155,13 +1231,33 @@ static void bq27x00_battery_poll(struct work_struct *work)  	}  } +static enum alarmtimer_restart  +bq27x00_run_poll_alarm(struct alarm * p_alarm, ktime_t now)  +{ +	struct bq27x00_device_info *di = +		container_of(p_alarm, struct bq27x00_device_info, poll_alarm); + +	olio_debug ("entered\n"); +	 +	wake_lock_timeout(&chg_wake_lock, msecs_to_jiffies(500)); + +	cancel_delayed_work(&di->work); +	schedule_delayed_work(&di->work, 5); + +	/* reschedule manually, since restart doesn't seem to do what we want. */ + +	alarm_start_relative (&di->poll_alarm, di->alarm_time); +	 +	return ALARMTIMER_NORESTART; +} +  /*   * Return the battery average current in µA   * Note that current can be negative signed as well   * Or 0 if something fails.   */  static int bq27x00_battery_current(struct bq27x00_device_info *di, -	union power_supply_propval *val) +				   union power_supply_propval *val)  {  	int curr;  	int flags; @@ -1190,7 +1286,36 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di,  #ifdef CONFIG_OLIO_TS81001 -static int bq27x00_charger_status(struct bq27x00_device_info *di) { +/* These are unfortunately hardcoded to our (OLIO's) GPIO pins right now. */ + +/* We need to turn off the wakeup capability of the pins when we don't  + * want the interrupts, or all heck breaks loose.  + */ + +static void olio_interrupt_enabled (int irq) { +	__raw_writew ((u16) (4 << 12 | 1 << 8 | 0 << 4 | 4),  +		      (volatile void *)  +		      OMAP2_L4_IO_ADDRESS(OMAP3_CONTROL_PADCONF_MUX_PBASE) +  +		      OMAP3_CONTROL_PADCONF_SYS_CLKOUT1_OFFSET); +	enable_irq (irq); +	enable_irq_wake (irq); +} + + +static void olio_interrupt_disabled (int irq) { +	disable_irq_wake (irq); +	disable_irq (irq); +	__raw_writew ((u16) (0 << 12 | 1 << 8 | 0 << 4 | 4),  +		      (volatile void *)  +		      OMAP2_L4_IO_ADDRESS(OMAP3_CONTROL_PADCONF_MUX_PBASE) +  +		      OMAP3_CONTROL_PADCONF_SYS_CLKOUT1_OFFSET); +} + + +static volatile int irq_enabled = 1; /* enabled from start */ + +static int bq27x00_charger_status (struct bq27x00_device_info *di,  +				   union power_supply_propval *val) {  	struct device * bq = di->dev;  	struct bq27x00_platform_data * pdata = bq->platform_data;  	struct ts81001 * ts81001; @@ -1207,9 +1332,21 @@ static int bq27x00_charger_status(struct bq27x00_device_info *di) {  	olio_debug("Got client data for dev %s\n", dev_name(ts81001->dev)); -	if(di->cache.flags & BQ27XXX_FLAG_CHG) { -		ts81001->ops->request_charge(ts81001); +#if 0 +	/* Test 1 */ +	if(di->cache.flags & BQ27XXX_FLAG_FC) { +		ts81001->ops->request_charge(ts81001, 100); +	} else { +		ts81001->ops->request_charge(ts81001, 390); +	} + +	/* Test 2 */ +	olio_debug ("mA_now == %d \n", mA_now); +	 +	if (mA_now < 0) { +		ts81001->ops->request_charge(ts81001, 100);  	} +#endif   	state = ts81001->ops->get_status(ts81001); @@ -1219,11 +1356,27 @@ static int bq27x00_charger_status(struct bq27x00_device_info *di) {  	{  	case NOT_CHARGING:  		olio_debug("exiting, DISCHARGING\n"); +		mutex_lock(&di->lock); +		if (!irq_enabled) { /* set up for off charger behavior */ +			olio_debug ("off charger, enabling chg interrupts\n"); +			irq_enabled = 1; +			olio_interrupt_enabled (di->irq); +			alarm_cancel (&di->poll_alarm); +		} +		mutex_unlock(&di->lock);  		return POWER_SUPPLY_STATUS_DISCHARGING;  	case PRECHARGE:  	case CHARGING_1C:  	case TOPOFF:  		olio_debug("exiting, CHARGING\n"); +		mutex_lock(&di->lock); +		if (irq_enabled) { /* set up for on charger behavior */ +			olio_debug ("on charger, disabling chg interrupts\n"); +			irq_enabled = 0; +			olio_interrupt_disabled (di->irq); +			alarm_start_relative (&di->poll_alarm, di->alarm_time); +		} +		mutex_unlock(&di->lock);  		return POWER_SUPPLY_STATUS_CHARGING;  	default:  		olio_debug("Couldn't read status from ts81001 charger.\n"); @@ -1231,7 +1384,6 @@ static int bq27x00_charger_status(struct bq27x00_device_info *di) {  		return POWER_SUPPLY_STATUS_UNKNOWN;  	}  } -  #endif  static int bq27x00_battery_status(struct bq27x00_device_info *di, @@ -1250,7 +1402,7 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di,  			status = POWER_SUPPLY_STATUS_DISCHARGING;  	} else {  #ifdef CONFIG_OLIO_TS81001 -		status = bq27x00_charger_status (di); +		status = bq27x00_charger_status (di, val);  		if(status == POWER_SUPPLY_STATUS_CHARGING &&   		   di->cache.flags & BQ27XXX_FLAG_FC) { @@ -1364,6 +1516,7 @@ static int bq27x00_battery_get_property(struct power_supply *psy,  		break;  	case POWER_SUPPLY_PROP_CURRENT_NOW:  		ret = bq27x00_battery_current(di, val); +		mA_now = val->intval;  		break;  	case POWER_SUPPLY_PROP_CAPACITY:  		ret = bq27x00_simple_value(di->cache.capacity, val); @@ -1416,6 +1569,7 @@ static int bq27x00_battery_get_property(struct power_supply *psy,  	return ret;  } +  static void bq27x00_external_power_changed(struct power_supply *psy)  {  	struct bq27x00_device_info *di = to_bq27x00_device_info(psy); @@ -1424,14 +1578,17 @@ static void bq27x00_external_power_changed(struct power_supply *psy)  	schedule_delayed_work(&di->work, 0);  } -static irqreturn_t bq27x00_chg_isr(int irq, void *dev) { +static irqreturn_t bq27x00_chg_isr(int irq, void *dev) {  	struct power_supply *ps = (struct power_supply*) dev; -	wake_lock_timeout(&chg_wake_lock, msecs_to_jiffies(500)); -	/* dev_dbg(ps->dev, "%s: Updating battery status\n", __func__);  Don't  -	   do i/o in interrupt! */ +	struct bq27x00_device_info *di = to_bq27x00_device_info(ps); + +	olio_debug ("ISR triggered!\n"); -	bq27x00_external_power_changed(ps); +	wake_lock(&isr_wake_lock); + +	cancel_delayed_work(&di->interrupt_work); +	schedule_delayed_work(&di->interrupt_work, 0);  	return IRQ_HANDLED;  } @@ -1476,6 +1633,18 @@ static int __init bq27x00_powersupply_init(struct bq27x00_device_info *di)  	di->bat.external_power_changed = bq27x00_external_power_changed;  	INIT_DELAYED_WORK(&di->work, bq27x00_battery_poll); +	INIT_DELAYED_WORK(&di->interrupt_work, bq27x00_battery_interrupt); + +#ifdef CONFIG_OLIO_TS81001 +	/* Set up alarm timer which wakes the device up if suspended. */ + +	alarm_init (&di->poll_alarm, ALARM_BOOTTIME,  +		    bq27x00_run_poll_alarm); + +	di->alarm_time = ktime_set(BQ27X00_ALARM_TIMER_INTERVAL,0); + +	alarm_start_relative (&di->poll_alarm, di->alarm_time); +#endif  	mutex_init(&di->lock);  	ret = power_supply_register(di->dev, &di->bat); @@ -1486,8 +1655,9 @@ static int __init bq27x00_powersupply_init(struct bq27x00_device_info *di)  	/* This device is a wakeup source */ -	device_init_wakeup(di->dev, 1); +	/* device_init_wakeup(di->dev, 1); */ +	wake_lock_init(&isr_wake_lock, WAKE_LOCK_SUSPEND, "isr_wake_lock");  	wake_lock_init(&chg_wake_lock, WAKE_LOCK_SUSPEND, "chg_wake_lock");  	if(di->irq) { @@ -1502,6 +1672,7 @@ static int __init bq27x00_powersupply_init(struct bq27x00_device_info *di)  		}  		ret = enable_irq_wake(di->irq); +  		if (ret) {  			dev_err(di->dev, "failed to enable irq: %d, as wake\n", di->irq);  			return ret; @@ -1526,6 +1697,7 @@ static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di)  	poll_interval = 0;  	cancel_delayed_work_sync(&di->work); +	cancel_delayed_work_sync(&di->interrupt_work);  	power_supply_unregister(&di->bat); @@ -1763,6 +1935,7 @@ static const struct attribute_group bq27x00_attr_group = {  #ifdef CONFIG_OLIO_TS81001 +  /***************************************************************************   * bq27x00_set_platform_data - act on basic platform data   *  @@ -1891,6 +2064,7 @@ static int __init bq27x00_battery_probe(struct i2c_client *client,  		goto batt_failed_3;  	/* Schedule a polling after about 1 min */ +	  	schedule_delayed_work(&di->work, 60 * HZ);  	i2c_set_clientdata(client, di); @@ -1944,8 +2118,8 @@ static struct i2c_driver bq27x00_battery_driver = {  	.driver = {  		.name = "bq27x00-battery",  	}, -	.probe = bq27x00_battery_probe, -	.remove = bq27x00_battery_remove, +	.probe    = bq27x00_battery_probe, +	.remove   = bq27x00_battery_remove,  	.id_table = bq27x00_id,  }; diff --git a/drivers/staging/triune/ts81001.c b/drivers/staging/triune/ts81001.c index 9ede65febc9..ed6f8abc78f 100644 --- a/drivers/staging/triune/ts81001.c +++ b/drivers/staging/triune/ts81001.c @@ -48,10 +48,20 @@  /* Globals */  -const int TS81001_ADDR=0x49; -const u8  TS81001_STATUS_REG=0x10; -const u8  TS81001_CURRENT_REG=0x20; -const u16 TS81001_CHARGE_CURRENT=390; +const int TS81001_ADDR = 0x49; +const u8  TS81001_STATUS_REG = 0x10; +const u8  TS81001_CURRENT_REG_LSB = 0x20; +const u8  TS81001_CURRENT_REG_MSB = 0x21; + +/* Trying 400mA since we can't actually set 390mA. */ + +const u16 TS81001_CHARGE_CURRENT = 400; +const u8  TS81001_CHARGE_CURRENT_LSB = 0x90; /* 0x190 == 400 (0x186 == 390)*/ +const u8  TS81001_CHARGE_CURRENT_MSB = 0x01;  + +const u8  TS81001_CHARGE_CURR_100_LSB = 0x64; /* 0x64 == 100 */ +const u8  TS81001_CHARGE_CURR_100_MSB = 0x00; +  /*************************************************************************** @@ -66,7 +76,7 @@ static int ts81001_i2c_read (struct i2c_client * client,  	int err = 0;  	struct i2c_msg msg[2]; -	olio_debug (" entered\n");	 +	olio_debug ("entered\n");	  	msg[0].addr = client->addr;  	msg[0].flags = client->flags; @@ -83,36 +93,42 @@ static int ts81001_i2c_read (struct i2c_client * client,  	else  		err = i2c_transfer(client->adapter, msg, 2); -	olio_debug (" exiting\n"); +	olio_debug ("exiting\n");  	return err;  } -static int ts81001_write_i2c_blk(struct i2c_client * client, u8 reg, -	u8 *data, u8 sz) +static int ts81001_write_i2c_blk(struct i2c_client * client, u8 reg_addr, +	u8 * data, u16 sz)  {  	struct i2c_msg msg;  	int ret; -	u8 buf[33]; +	u8 buf[3]; + +	olio_debug ("entered\n");  	if (!client->adapter)  		return -ENODEV; -	buf[0] = reg; +	buf[0] = reg_addr;  	memcpy(&buf[1], data, sz); -	msg.buf = buf; +	olio_debug ("writing 0x%x,0x%x to 0x%x device 0x%x\n", +		    buf[1], buf[2], buf[0], client->addr); +  	msg.addr = client->addr; -	msg.flags = 0; +	msg.flags = 0; //client->flags;  	msg.len = sz + 1; +	msg.buf = buf;  	ret = i2c_transfer(client->adapter, &msg, 1); -	if (ret < 0) -		return ret; +	 +	olio_debug ("exiting, ret = %d\n", ret); -	return 0; +	return ret;  } +  /***************************************************************************   * ts81001_get_status - get current charger state.   *  @@ -132,10 +148,11 @@ static int ts81001_get_status (struct ts81001 * ts) {  	olio_debug ("entered\n");  	for (i = 0; i < retries; i++) { -		err = ts81001_i2c_read (ts->client, TS81001_STATUS_REG, len, &data, false); -	 +		err = ts81001_i2c_read (ts->client,  +					TS81001_STATUS_REG, len, &data, false);  		if (err <= 0) { -			olio_debug ("Error reading status from ts81001, err = %d\n", err); +			olio_debug ("Error reading status from ts81001, err = %d\n",  +				    err);  			state = err;  		} else {  			state = (ts81001_state_t) data; @@ -148,32 +165,237 @@ static int ts81001_get_status (struct ts81001 * ts) {  	return state;  } -static int ts81001_request_charge (struct ts81001 * ts) { +/*************************************************************************** + * ts81001_request_charge - ask for current from charger + *  + * This function allows us to set a new current for the charger. It depends + * on the firmware being recent enough, though. Returns the number of bytes + * written, or error (negative values) if needed.  + */ + +static int ts81001_request_charge (struct ts81001 * ts, u16 mA) {  	int retries = 2;  	int err = 0;  	int i; -	u16 request_current = TS81001_CHARGE_CURRENT; +	/* u16 request_current = TS81001_CHARGE_CURRENT; */ +	u8 data[2]; + +	data[0] = mA & 0x00ff; +	data[1] = (mA & 0xff00) >> 8; + +	printk ("OLIO %s entered, requested current = lb:0x%x, hb:0x%x\n",  +		__FUNCTION__, data[0], data[1]); +	 +	for (i = 0; i < retries; i++) { +		err = ts81001_write_i2c_blk(ts->client,  +					    TS81001_CURRENT_REG_LSB, +					    &data[0], 2); +		if (err <= 0) +			olio_debug ("error (%d) writing data to " +				    "register (try = %d)\n", err, i); +	} +	 +	return err; +} + +/*************************************************************************** + * ts81001_charging_stop - send charge complete to power provider + * + * This function allows to stop charging - stopping and restarting charging + * is intended to simulate the device taken off the charger and put back on. + */ + +#define TS81001_CHARGE_COMPLETE 0x01 +#define TS81001_STATE_REPORT_REG 0x12 + +static int ts81001_charging_stop (struct ts81001 * ts) { +	u8 data; +	int len = 1; +	int err = 0; +	int i, retries = 2; + +	olio_debug ("entered\n"); +	 +	data = TS81001_CHARGE_COMPLETE; + +	for (i = 0; i < retries; i++) { +		err = ts81001_write_i2c_blk(ts->client, TS81001_STATE_REPORT_REG, +					    (u8*) &data, len); +	} + +	if (err <= 0) { +		olio_debug ("Error writing charging stop to ts81001, " +			"err = %d\n", err); +	} +	 + +	olio_debug ("exiting\n"); + +	return err; +} + + +/*************************************************************************** + * ts81001_charging_stop - send charge complete to power provider + * + * This function allows to stop charging - stopping and restarting charging + * is intended to simulate the device taken off the charger and put back on. + */ + +#define TS81001_CHARGE_RESTART 0xFF + +static int ts81001_charging_restart (struct ts81001 * ts) { +	u8 data; +	int len = 1; +	int err = 0; +	int i, retries = 2; + +	olio_debug ("entered\n"); + +	data = TS81001_CHARGE_RESTART;  	for (i = 0; i < retries; i++) { -		err = ts81001_write_i2c_blk(ts->client, TS81001_CURRENT_REG, (u8*) &request_current, 2); +		err = ts81001_write_i2c_blk(ts->client,  +					    TS81001_STATE_REPORT_REG, +					    (u8*) &data, len); + +		if (err <= 0) { +		        olio_debug ("Error writing state to ts81001, " +				"err = %d\n", err); +		}  	} +	olio_debug ("exiting\n"); +  	return err;  } +#if 0 + +/* NOT FUNCTIONAL, NOT SURE HOW TO MAKE IT FUNCTIONAL! */ + +/*************************************************************************** + * ts81001_disconnect - stop talking to power TX + * + * If we send a 'signal strength' package, the TX unit should forget that  + * we've reached full charge. + */ + +static int ts81001_disconnect (struct ts81001 * ts) { +	u8 data; +	int len = 1; +	int err = 0; +	int i, retries = 2; + +	olio_debug ("entered\n"); + +	data = TS81001_CHARGE_RESTART; + +	for (i = 0; i < retries; i++) { +		err = ts81001_write_i2c_blk(ts->client,  +					    TS81001_STATE_REPORT_REG, +					    (u8*) &data, len); + +		if (err <= 0) { +		        olio_debug ("Error writing state to ts81001, " +				"err = %d\n", err); +		} +	} + +	olio_debug ("exiting\n"); + +	return err; +} +#endif  static struct ts81001_ops ts_ops = { -	.get_status = ts81001_get_status, +	.get_status     = ts81001_get_status,  	.request_charge = ts81001_request_charge, +	.charge_stop    = ts81001_charging_stop, +	.charge_start   = ts81001_charging_restart,  }; + + +/*************************************************************************** + * sysfs operations + ***************************************************************************/ + +/* sysfs entry for requesting power, mA's. */ + +/*************************************************************************** + * ts81001_sysfs_set_power_request - request power level from TX + *  + * This entry allows us to request a certain power level from the TX unit. + * Mainly used for testing. + */ + +static ssize_t ts81001_sysfs_set_power_request ( +	struct device * dev, +	struct device_attribute * attr, +	const char * buf,  +	size_t count)  +{ +	int mA_req; +	int s; +	u16 mA; +	ssize_t retval = 0; + +	struct ts81001 * ts81001 =  +		i2c_get_clientdata (to_i2c_client (dev)); +	 +	if ((s = sscanf (buf, "%d\n", &mA_req)) != 1) { +		printk ("%s OLIO wrong number of args (%d, expected 1) " +			"for power request.\n", __FUNCTION__, s); +		retval = -EINVAL; +		goto done; +	} else { +		printk ("%s OLIO read %d for new power level\n",  +			__FUNCTION__, mA_req); +	} + +	if (mA_req > 0xffff) { +		printk ("%s OLIO warning, max request is %d.\n", +			__FUNCTION__, 0xffff); +		mA_req = 0xffff; +	} + +	mA = (u16) mA_req; +	 +	retval = ts81001_request_charge (ts81001, mA); + +done: +	return count; +} + +/*************************************************************************** + * ts81001_sysfs_show_power_request - show the power level last requested + *  + * This sysfs entry will read the value of the power request registers in + * the ts81001 and return it.  + */ + +static ssize_t ts81001_sysfs_show_power_request (struct device * dev,  +						 struct device_attribute * attr, +						 char * buf) { +	 +	return 0; +} + +static struct device_attribute ts81001_device_attr = +	__ATTR(ts81001_power_request, S_IWUGO | S_IRUGO,  +	       ts81001_sysfs_show_power_request, +	       ts81001_sysfs_set_power_request); + + +  /***************************************************************************   * probe   */  static int ts81001_i2c_probe(struct i2c_client * client,  -			 const struct i2c_device_id * id) +			     const struct i2c_device_id * id)  {  	struct ts81001 *ts81001; @@ -198,6 +420,8 @@ static int ts81001_i2c_probe(struct i2c_client * client,  	i2c_set_clientdata(client, ts81001); +	device_create_file (ts81001->dev, &ts81001_device_attr); +  	olio_debug ("exiting\n");  	return ret; @@ -230,6 +454,6 @@ static struct i2c_driver ts81001_i2c_driver = {  module_i2c_driver(ts81001_i2c_driver); -MODULE_AUTHOR("Mattis Fjallstrom <mattis@oliodevice.com"); +MODULE_AUTHOR("Mattis Fjallstrom <mattis@oliodevices.com");  MODULE_DESCRIPTION("Basic driver for TS81001");  MODULE_LICENSE("GPL"); diff --git a/drivers/staging/triune/ts81001.h b/drivers/staging/triune/ts81001.h index 8978ca2f0d1..aecf19780cc 100644 --- a/drivers/staging/triune/ts81001.h +++ b/drivers/staging/triune/ts81001.h @@ -52,7 +52,9 @@ struct ts81001 {  struct ts81001_ops {  	int (*get_status) (struct ts81001 * ts); -	int (*request_charge) (struct ts81001 * ts); +	int (*request_charge) (struct ts81001 * ts, u16 charge); +	int (*charge_stop) (struct ts81001 * ts); +	int (*charge_start) (struct ts81001 * ts);  };  #endif /* _CONFIG_TS81001_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 50ff7ca10a9..113ee1f928c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -41,6 +41,7 @@ config SND_SOC_ALL_CODECS  	select SND_SOC_DA732X if I2C  	select SND_SOC_DA9055 if I2C  	select SND_SOC_DFBMCS320 +	select SND_SOC_OMAP3H1_BT_SCO  	select SND_SOC_ISABELLE if I2C  	select SND_SOC_JZ4740_CODEC  	select SND_SOC_LM4857 if I2C @@ -266,6 +267,9 @@ config SND_SOC_DA9055  config SND_SOC_DFBMCS320  	tristate +config SND_SOC_OMAP3H1_BT_SCO +	tristate +  config SND_SOC_DMIC  	tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 39747d34c41..8e7bb4d4cbe 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -29,6 +29,7 @@ snd-soc-da7213-objs := da7213.o  snd-soc-da732x-objs := da732x.o  snd-soc-da9055-objs := da9055.o  snd-soc-dfbmcs320-objs := dfbmcs320.o +snd-soc-omap3h1_bt_sco-objs := omap3h1_bt_sco.o  snd-soc-dmic-objs := dmic.o  snd-soc-isabelle-objs := isabelle.o  snd-soc-jz4740-codec-objs := jz4740.o @@ -157,6 +158,7 @@ obj-$(CONFIG_SND_SOC_DA7213)	+= snd-soc-da7213.o  obj-$(CONFIG_SND_SOC_DA732X)	+= snd-soc-da732x.o  obj-$(CONFIG_SND_SOC_DA9055)	+= snd-soc-da9055.o  obj-$(CONFIG_SND_SOC_DFBMCS320)	+= snd-soc-dfbmcs320.o +obj-$(CONFIG_SND_SOC_OMAP3H1_BT_SCO)	+= snd-soc-omap3h1_bt_sco.o  obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o  obj-$(CONFIG_SND_SOC_ISABELLE)	+= snd-soc-isabelle.o  obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o diff --git a/sound/soc/codecs/omap3h1_bt_sco.c b/sound/soc/codecs/omap3h1_bt_sco.c new file mode 100644 index 00000000000..f72f004f64c --- /dev/null +++ b/sound/soc/codecs/omap3h1_bt_sco.c @@ -0,0 +1,74 @@ +/* + * Driver for the DFBM-CS320 bluetooth module + * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de> + * + *  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. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <sound/soc.h> + +int omap3h1_bt_sco_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ +    printk ("OMAP3H1:ASoc %s:%s starting\n", __FILE__, __FUNCTION__); +    return 0; +} + +void omap3h1_bt_sco_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ +    printk ("OMAP3H1:ASoc %s:%s shutting down\n", __FILE__, __FUNCTION__); +} + +static struct snd_soc_dai_ops omap3h1_bt_sco_dai_ops = { +		.startup	= omap3h1_bt_sco_dai_startup, +		.shutdown	= omap3h1_bt_sco_dai_shutdown, +}; + +static struct snd_soc_dai_driver omap3h1_bt_sco_dai = { +	.name = "omap3h1_bt_sco-pcm", +	.playback = { +		.channels_min = 1, +		.channels_max = 2, +		.rates = SNDRV_PCM_RATE_8000, +		.formats = SNDRV_PCM_FMTBIT_S32_LE, +	}, +	.ops = &omap3h1_bt_sco_dai_ops, +}; + +static struct snd_soc_codec_driver soc_codec_dev_omap3h1_bt_sco; + +static int omap3h1_bt_sco_probe(struct platform_device *pdev) +{ +	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_omap3h1_bt_sco, +			&omap3h1_bt_sco_dai, 1); +} + +static int omap3h1_bt_sco_remove(struct platform_device *pdev) +{ +	snd_soc_unregister_codec(&pdev->dev); + +	return 0; +} + + +static struct platform_driver omap3h1_bt_sco = { +	.driver = { +		.name = "omap3h1_bt_sco", +		.owner = THIS_MODULE, +	}, +	.probe = omap3h1_bt_sco_probe, +	.remove = omap3h1_bt_sco_remove, +}; + +module_platform_driver(omap3h1_bt_sco); + +MODULE_AUTHOR("Evan Wilson <evan@oliodevices.com"); +MODULE_DESCRIPTION("OMAP3 H1 ALSA SoC codec driver"); +MODULE_LICENSE("GPL");
\ No newline at end of file diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 66d98e26a24..08c94b19bb9 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -31,6 +31,7 @@ config SND_OMAP_SOC_OMAP3_H1  	depends on SND_OMAP_SOC && MACH_OMAP3_H1  	select SND_OMAP_SOC_MCBSP  	select SND_SOC_DMIC +	select SND_SOC_OMAP3H1_BT_SCO  	help  	  Say Y if you want to add support for SoC audio on the Olio H1 board. diff --git a/sound/soc/omap/omap3h1.c b/sound/soc/omap/omap3h1.c index f61949b295e..faad74810c3 100644 --- a/sound/soc/omap/omap3h1.c +++ b/sound/soc/omap/omap3h1.c @@ -22,7 +22,7 @@   *   */ -#define DEBUG +//#define DEBUG  #include <linux/clk.h>  #include <linux/gpio.h>  #include <linux/of_gpio.h> @@ -42,19 +42,22 @@ static struct clk *per_96m_fck;  static unsigned long rate;  static int mic_gpio_enable; -static int omap3h1_hw_params(struct snd_pcm_substream *substream, +static int omap3h1_hw_in_params(struct snd_pcm_substream *substream,  	struct snd_pcm_hw_params *params)  {  	struct snd_soc_pcm_runtime *rtd = substream->private_data;  	struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -	//unsigned int fmt;  	int ret = 0; -	unsigned int freq; -	//freq = 256 * params_rate(params); -    // We are triggering from the 96 MHz FSCK +	pr_info("ASoc OMAP3H1: omap3h1_hw_in_params\n"); +	pr_info("ASoc OMAP3H1: in params channels=%d\n", params_channels(params)); +	pr_info("ASoc OMAP3H1: in params rate=%d\n", params_rate(params)); +	pr_info("ASoc OMAP3H1: in params params_period_size=%d\n", params_period_size(params)); +	pr_info("ASoc OMAP3H1: in params params_periods=%d\n", params_periods(params)); +	pr_info("ASoc OMAP3H1: in params params_buffer_size=%d\n", params_buffer_size(params)); +	pr_info("ASoc OMAP3H1: in params params_buffer_bytes=%d\n", params_buffer_bytes(params)); -	// pr_info("ASoc OMAP3H1: setting system clock to: %d", freq); +	/* Set McBSP clock to use PER_96M_FCLK */  	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_FCLK,  			rate, SND_SOC_CLOCK_OUT);  	if (ret < 0) { @@ -62,68 +65,121 @@ static int omap3h1_hw_params(struct snd_pcm_substream *substream,  		return ret;  	} -	// Set the divider so that our clock rate is ~3KHz, this is about  -    // 48KHz sampling frequency on the mic (32-bit/channel, 2 channels, 48  -    // Khz sampling) +	/* The microphone becomes operational 2^18 clock cycles */ +        /* (85 ms with SCK at 3.072 MHz) */  	ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 32);  	if (ret < 0) { -		pr_err("ASoc OMAP3H1: can't set SRG clock divider\n"); +		pr_err("ASoc OMAP3H1: can't set MIC clock divider\n");  		return ret;  	}  	return 0;  } -static int omap3h1_startup(struct snd_pcm_substream *substream) +static int omap3h1_hw_out_params(struct snd_pcm_substream *substream, +	struct snd_pcm_hw_params *params) +{ +	struct snd_soc_pcm_runtime *rtd = substream->private_data; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai; +	int ret = 0; + +	pr_info("ASoc OMAP3H1: omap3h1_hw_out_params"); +	pr_info("ASoc OMAP3H1: out params channels=%u\n", params_channels(params)); +	pr_info("ASoc OMAP3H1: out params rate=%u\n", params_rate(params)); +	pr_info("ASoc OMAP3H1: out params params_period_size=%u\n", params_period_size(params)); +	pr_info("ASoc OMAP3H1: out params params_periods=%u\n", params_periods(params)); +	pr_info("ASoc OMAP3H1: out params params_buffer_size=%u\n", params_buffer_size(params)); +	pr_info("ASoc OMAP3H1: out params params_buffer_bytes=%u\n", params_buffer_bytes(params)); + +	/* Set McBSP clock to use PER_96M_FCLK */ +	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_FCLK, +			rate, SND_SOC_CLOCK_OUT); +	if (ret < 0) { +		printk(KERN_ERR "can't set DMIC cpu system clock\n"); +		return ret; +	} + +	/* The BT operates on 512K freq */ +	ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, rate/512000); +	if (ret < 0) { +		pr_err("ASoc OMAP3H1: can't set BT clock divider\n"); +		return ret; +	} + +	return 0; +} + + +static int omap3h1_in_startup(struct snd_pcm_substream *substream)  { +	pr_info("ASoc OMAP3H1: omap3h1_in_startup");  	gpio_set_value(mic_gpio_enable, 1);  	return clk_enable(per_96m_fck);  } -static void omap3h1_shutdown(struct snd_pcm_substream *substream) +static void omap3h1_in_shutdown(struct snd_pcm_substream *substream)  { +	pr_info("ASoc OMAP3H1: omap3h1_in_shutdown");  	gpio_set_value(mic_gpio_enable, 0);  	clk_disable(per_96m_fck);  } -static struct snd_soc_ops omap3h1_ops = { -	.hw_params = omap3h1_hw_params, -	.startup = omap3h1_startup, -	.shutdown = omap3h1_shutdown, +static int omap3h1_out_startup(struct snd_pcm_substream *substream) +{ +	pr_info("ASoc OMAP3H1: omap3h1_out_startup"); +	return clk_enable(per_96m_fck); +} + +static void omap3h1_out_shutdown(struct snd_pcm_substream *substream) +{ +	pr_info("ASoc OMAP3H1: omap3h1_out_shutdown"); +	clk_disable(per_96m_fck); +} + +static struct snd_soc_ops omap3h1_in_ops = { +	.hw_params = omap3h1_hw_in_params, +	.startup = omap3h1_in_startup, +	.shutdown = omap3h1_in_shutdown,  }; -//static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = { -//	SND_SOC_DAPM_MIC("Digital Mic", NULL), -//}; -// -//static const struct snd_soc_dapm_route dmic_audio_map[] = { -//	{"DMic", NULL, "Digital Mic"}, -//}; +static struct snd_soc_ops omap3h1_out_ops = { +	.hw_params = omap3h1_hw_out_params, +	.startup = omap3h1_out_startup, +	.shutdown = omap3h1_out_shutdown, +};  /* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap3h1_dai = { -		.name = "DMIC", -		.stream_name = "DMIC Capture", -		.cpu_dai_name = "omap-mcbsp.3", -		.codec_dai_name = "dmic-hifi", -		.platform_name = "omap-pcm-audio", -		.codec_name = "dmic-codec", -		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -				SND_SOC_DAIFMT_CBS_CFS, -		.ops = &omap3h1_ops, +static struct snd_soc_dai_link omap3h1_dai[] = { +	{ +			.name = "DMIC", +			.stream_name = "DMIC Capture", +			.cpu_dai_name = "omap-mcbsp.3", +			.codec_dai_name = "dmic-hifi", +			.platform_name = "omap-pcm-audio", +			.codec_name = "dmic-codec", +			.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | +			SND_SOC_DAIFMT_CBS_CFS, +			.ops = &omap3h1_in_ops, +	}, +	{ +			.name = "BT", +			.stream_name = "BT Playback", +			.cpu_dai_name = "omap-mcbsp.2", +			.codec_dai_name = "omap3h1_bt_sco-pcm", +			.platform_name = "omap-pcm-audio", +			.codec_name = "omap3h1_bt_sco", +			.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | +			SND_SOC_DAIFMT_CBS_CFS, +			.ops = &omap3h1_out_ops, +	}  };  /* Audio machine driver */  static struct snd_soc_card snd_soc_omap3h1 = {  	.name = "omap3h1",  	.owner = THIS_MODULE, -	.dai_link = &omap3h1_dai, -	.num_links = 1, - -//	.dapm_widgets = dmic_dapm_widgets, -//	.num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets), -//	.dapm_routes = dmic_audio_map, -//	.num_dapm_routes = ARRAY_SIZE(dmic_audio_map), +	.dai_link = omap3h1_dai, +	.num_links = ARRAY_SIZE(omap3h1_dai),  };  static int omap3h1_card_probe(struct platform_device *pdev) @@ -135,15 +191,24 @@ static int omap3h1_card_probe(struct platform_device *pdev)  #ifdef CONFIG_OF  	if (node) { -		struct device_node *dai_node; +		struct device_node *dai_node1; +		struct device_node *dai_node2; + +		dai_node1 = of_parse_phandle(node, "olio,mcbsp_mic", 0); +		if (!dai_node1) { +			dev_err(&pdev->dev, "mcbsp3 node is not provided\n"); +			return -EINVAL; +		} +		omap3h1_dai[0].cpu_dai_name = NULL; +		omap3h1_dai[0].cpu_of_node = dai_node1; -		dai_node = of_parse_phandle(node, "olio,mcbsp", 0); -		if (!dai_node) { -			dev_err(&pdev->dev, "mcbsp node is not provided\n"); +		dai_node2 = of_parse_phandle(node, "olio,mcbsp_bt", 0); +		if (!dai_node2) { +			dev_err(&pdev->dev, "mcbsp2 node is not provided\n");  			return -EINVAL;  		} -		omap3h1_dai.cpu_dai_name = NULL; -		omap3h1_dai.cpu_of_node = dai_node; +		omap3h1_dai[1].cpu_dai_name = NULL; +		omap3h1_dai[1].cpu_of_node = dai_node2;  	} else {  		dev_err(&pdev->dev, "Missing node\n"); @@ -191,52 +256,18 @@ static int omap3h1_card_remove(struct platform_device *pdev)  	return 0;  } -/** - * omap3h1_sound_suspend - suspend microphone - *  - */ - -static int omap3h1_sound_suspend(struct device *dev) { -    printk ("OLIO %s:%s Suspending\n", __FILE__, __FUNCTION__); - -    snd_soc_suspend(dev); - -    return 0; -} - - -/** - * omap3h1_sound_resume - resume microphone - *  - */ - -static int omap3h1_sound_resume(struct device *dev) { -    printk ("OLIO %s:%s Resuming\n", __FILE__, __FUNCTION__); - -    snd_soc_resume (dev); - -    return 0; -} - - -/* ---------------------------------------------------------------------- */ - -static const struct dev_pm_ops omap3h1_sound_pm_ops = { -    SET_SYSTEM_SLEEP_PM_OPS(omap3h1_sound_suspend, omap3h1_sound_resume) -}; - -  static const struct of_device_id omap_soc_h1_of_match[] = {  	{.compatible = "olio,omap-soc-omap3h1", },  	{ },  }; +  MODULE_DEVICE_TABLE(of, omap_soc_h1_of_match);  static struct platform_driver omap3h1_driver = {  	.driver = {  		.name	= "omap-soc-omap3h1",  		.of_match_table = of_match_ptr(omap_soc_h1_of_match), -        .pm = &snd_soc_pm_ops, +		.pm = &snd_soc_pm_ops,  	},  	.probe		= omap3h1_card_probe,  	.remove		= omap3h1_card_remove, |