From: guiming zhuo <gmzhuo@gbsoft.localdomain>
Subject: [PATCH] ezx/rfkill

add rfkill api for bluetooth

Signed-off-by: guiming zhuo <gmzhuo@gbsoft.localdomain>

---
 drivers/mfd/ezx-pcap.c |  187 ++++++++++++++++++++++++++++++++++-------------
 1 files changed, 135 insertions(+), 52 deletions(-)

diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c
index 836a9ed..e9f1372 100644
--- a/drivers/mfd/ezx-pcap.c
+++ b/drivers/mfd/ezx-pcap.c
@@ -17,12 +17,15 @@
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/spi/spi.h>
+#include <linux/rfkill.h>
 
 struct pcap_chip {
 	struct spi_device *spi;
+	struct rfkill *rf_kill;
+	char rf_kill_name[60];
 	struct work_struct work;
 	struct workqueue_struct *workqueue;
-	void (*adc_done)(void *);
+	void (*adc_done) (void *);
 	void *adc_data;
 };
 static struct pcap_chip pcap;
@@ -64,18 +67,20 @@ int ezx_pcap_write(u8 reg_num, u32 value)
 {
 	value &= PCAP_REGISTER_VALUE_MASK;
 	value |= PCAP_REGISTER_WRITE_OP_BIT
-		| (reg_num << PCAP_REGISTER_ADDRESS_SHIFT);
+	    | (reg_num << PCAP_REGISTER_ADDRESS_SHIFT);
 	return ezx_pcap_putget(&value);
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_write);
 
 int ezx_pcap_read(u8 reg_num, u32 *value)
 {
 	*value = PCAP_REGISTER_READ_OP_BIT
-		| (reg_num << PCAP_REGISTER_ADDRESS_SHIFT);
+	    | (reg_num << PCAP_REGISTER_ADDRESS_SHIFT);
 
 	return ezx_pcap_putget(value);
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_read);
 
 /* Voltage regulators */
@@ -88,29 +93,30 @@ int ezx_pcap_set_sw(u8 sw, u8 what, u8 val)
 	tmp |= ((val & 0xf) << (sw + what));
 	return ezx_pcap_write(PCAP_REG_LOWPWR, tmp);
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_set_sw);
 
 static u8 vreg_table[][5] = {
-	/*		EN	INDEX	MASK	STBY	LOWPWR	*/
-	[V1]	= {	1,	2,	0x7,	18,	0,	},
-	[V2]	= {	5,	6,	0x1,	19,	22,	},
-	[V3]	= {	7,	8,	0x7,	20,	23,	},
-	[V4]	= {	11,	12,	0x7,	21,	24,	},
-	[V5]	= {	15,	16,	0x3,	0xff,	0xff,	},
-	[V6]	= {	1,	0xff,	0x0,	0xff,	0xff,	},
+	/*              EN      INDEX   MASK    STBY    LOWPWR  */
+	[V1] = {1, 2, 0x7, 18, 0,},
+	[V2] = {5, 6, 0x1, 19, 22,},
+	[V3] = {7, 8, 0x7, 20, 23,},
+	[V4] = {11, 12, 0x7, 21, 24,},
+	[V5] = {15, 16, 0x3, 0xff, 0xff,},
+	[V6] = {1, 0xff, 0x0, 0xff, 0xff,},
 	/* FIXME: I have no idea of V7-V10 bits -WM */
-	[V7]	= {	0xff,	0xff,	0x0,	0xff,	0xff,	},
-	[V8]	= {	0xff,	0xff,	0x0,	0xff,	0xff,	},
-	[V9]	= {	0xff,	0xff,	0x0,	0xff,	0xff,	},
-	[V10]	= {	0xff,	0xff,	0x0,	0xff,	0xff,	},
-	[VAUX1]	= {	1,	2,	0x3,	22,	23,	},
-	[VAUX2]	= {	4,	5,	0x3,	0,	1,	},
-	[VAUX3]	= {	7,	8,	0xf,	2,	3,	},
-	[VAUX4]	= {	12,	13,	0x3,	4,	5,	},
-	[VSIM]	= {	17,	18,	0x1,	0xff,	6,	},
-	[VSIM2]	= {	16,	0xff,	0x0,	0xff,	7,	},
-	[VVIB]	= {	19,	20,	0x3,	0xff,	0xff,	},
-	[VC]	= {	0xff,	0xff,	0x0,	24,	0xff,	},
+	[V7] = {0xff, 0xff, 0x0, 0xff, 0xff,},
+	[V8] = {0xff, 0xff, 0x0, 0xff, 0xff,},
+	[V9] = {0xff, 0xff, 0x0, 0xff, 0xff,},
+	[V10] = {0xff, 0xff, 0x0, 0xff, 0xff,},
+	[VAUX1] = {1, 2, 0x3, 22, 23,},
+	[VAUX2] = {4, 5, 0x3, 0, 1,},
+	[VAUX3] = {7, 8, 0xf, 2, 3,},
+	[VAUX4] = {12, 13, 0x3, 4, 5,},
+	[VSIM] = {17, 18, 0x1, 0xff, 6,},
+	[VSIM2] = {16, 0xff, 0x0, 0xff, 7,},
+	[VVIB] = {19, 20, 0x3, 0xff, 0xff,},
+	[VC] = {0xff, 0xff, 0x0, 24, 0xff,},
 };
 
 int ezx_pcap_set_vreg(u8 vreg, u8 what, u8 val)
@@ -120,16 +126,16 @@ int ezx_pcap_set_vreg(u8 vreg, u8 what, u8 val)
 	u32 tmp;
 
 	switch (vreg) {
-	case V1 ... V5:
+	case V1...V5:
 		/* vreg1 is not accessible on port 2 */
 		if (pdata->config & PCAP_SECOND_PORT)
 			return -EINVAL;
 		reg = PCAP_REG_VREG1;
 		break;
-	case V6 ... V10:
+	case V6...V10:
 		reg = PCAP_REG_VREG2;
 		break;
-	case VAUX1 ... VC:
+	case VAUX1...VC:
 		if ((what == V_LOWPWR || what == V_STBY) && vreg != VAUX1)
 			reg = PCAP_REG_LOWPWR;
 		else
@@ -165,6 +171,7 @@ int ezx_pcap_set_vreg(u8 vreg, u8 what, u8 val)
 
 	return 0;
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_set_vreg);
 
 /* ADC */
@@ -173,7 +180,8 @@ void ezx_pcap_disable_adc(void)
 	u32 tmp;
 
 	ezx_pcap_read(PCAP_REG_ADC, &tmp);
-	tmp &= ~(PCAP_ADC_ADEN|PCAP_ADC_BATT_I_ADC|PCAP_ADC_BATT_I_POLARITY);
+	tmp &=
+	    ~(PCAP_ADC_ADEN | PCAP_ADC_BATT_I_ADC | PCAP_ADC_BATT_I_POLARITY);
 	tmp |= (PCAP_ADC_TS_M_STANDBY << PCAP_ADC_TS_M_SHIFT);
 	ezx_pcap_write(PCAP_REG_ADC, tmp);
 	mutex_unlock(&adc_lock);
@@ -181,7 +189,7 @@ void ezx_pcap_disable_adc(void)
 
 static void ezx_pcap_adc_event(u32 flags, void *data)
 {
-	void (*adc_done)(void *);
+	void (*adc_done) (void *);
 	void *adc_data;
 
 	if (!pcap.adc_done)
@@ -196,7 +204,7 @@ static void ezx_pcap_adc_event(u32 flags, void *data)
 }
 
 void ezx_pcap_start_adc(u8 bank, u8 time, u32 flags,
-						void *adc_done, void *adc_data)
+			void *adc_done, void *adc_data)
 {
 	u32 adc;
 	u32 adr;
@@ -231,6 +239,7 @@ void ezx_pcap_start_adc(u8 bank, u8 time, u32 flags,
 	adr |= PCAP_ADR_ONESHOT;
 	ezx_pcap_write(PCAP_REG_ADR, adr);
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_start_adc);
 
 void ezx_pcap_get_adc_channel_result(u8 ch1, u8 ch2, u32 res[])
@@ -245,6 +254,7 @@ void ezx_pcap_get_adc_channel_result(u8 ch1, u8 ch2, u32 res[])
 	res[0] = (tmp & PCAP_ADR_ADD1_MASK) >> PCAP_ADR_ADD1_SHIFT;
 	res[1] = (tmp & PCAP_ADR_ADD2_MASK) >> PCAP_ADR_ADD2_SHIFT;
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_get_adc_channel_result);
 
 void ezx_pcap_get_adc_bank_result(u32 res[])
@@ -253,14 +263,15 @@ void ezx_pcap_get_adc_bank_result(u32 res[])
 	u32 tmp[2];
 
 	for (x = 0; x < 7; x += 2) {
-		ezx_pcap_get_adc_channel_result(x, (x+1) % 6, tmp);
+		ezx_pcap_get_adc_channel_result(x, (x + 1) % 6, tmp);
 		res[x] = tmp[0];
 		if ((x + 1) < 7)
-			res[x+1] = tmp[1];
+			res[x + 1] = tmp[1];
 		else
-			res[x+1] = 0;
+			res[x + 1] = 0;
 	}
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_get_adc_bank_result);
 
 static void adc_complete(void *data)
@@ -280,6 +291,7 @@ void ezx_pcap_do_general_adc(u8 bank, u8 ch, u32 *res)
 
 	*res = tmp[0];
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_do_general_adc);
 
 void ezx_pcap_do_batt_adc(int pol, u32 res[])
@@ -288,10 +300,10 @@ void ezx_pcap_do_batt_adc(int pol, u32 res[])
 	DECLARE_COMPLETION_ONSTACK(done);
 
 	ezx_pcap_start_adc(PCAP_ADC_BANK_0, PCAP_ADC_T_NOW,
-				PCAP_ADC_RAND | PCAP_ADC_BATT_I_ADC |
-				(PCAP_ADC_CH_BATT << PCAP_ADC_ADA1_SHIFT) |
-				(pol ? PCAP_ADC_BATT_I_POLARITY : 0),
-				adc_complete, &done);
+			   PCAP_ADC_RAND | PCAP_ADC_BATT_I_ADC |
+			   (PCAP_ADC_CH_BATT << PCAP_ADC_ADA1_SHIFT) |
+			   (pol ? PCAP_ADC_BATT_I_POLARITY : 0),
+			   adc_complete, &done);
 	wait_for_completion(&done);
 	ezx_pcap_get_adc_bank_result(tmp);
 	ezx_pcap_disable_adc();
@@ -301,6 +313,7 @@ void ezx_pcap_do_batt_adc(int pol, u32 res[])
 	res[1] = (tmp[1] + tmp[3] + tmp[5]) / 3;
 	res[1] = (res[1] - 178) * 3165 / 1000;
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_do_batt_adc);
 
 /* event handling */
@@ -340,6 +353,7 @@ void ezx_pcap_mask_event(u32 events)
 	msr |= events;
 	ezx_pcap_write(PCAP_REG_MSR, msr);
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_mask_event);
 
 void ezx_pcap_unmask_event(u32 events)
@@ -350,6 +364,7 @@ void ezx_pcap_unmask_event(u32 events)
 	msr &= ~events;
 	ezx_pcap_write(PCAP_REG_MSR, msr);
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_unmask_event);
 
 int ezx_pcap_register_event(u32 events, void *callback, void *data, char *label)
@@ -372,6 +387,7 @@ int ezx_pcap_register_event(u32 events, void *callback, void *data, char *label)
 	ezx_pcap_unmask_event(events);
 	return 0;
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_register_event);
 
 int ezx_pcap_unregister_event(u32 events)
@@ -393,11 +409,12 @@ int ezx_pcap_unregister_event(u32 events)
 	mutex_unlock(&event_lock);
 	return ret;
 }
+
 EXPORT_SYMBOL_GPL(ezx_pcap_unregister_event);
 
 /* sysfs interface */
 static ssize_t pcap_show_regs(struct device *dev,
-			struct device_attribute *attr, char *buf)
+			      struct device_attribute *attr, char *buf)
 {
 	unsigned int reg, val;
 	char *p = buf;
@@ -410,14 +427,15 @@ static ssize_t pcap_show_regs(struct device *dev,
 }
 
 static ssize_t pcap_store_regs(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t size)
+			       struct device_attribute *attr, const char *buf,
+			       size_t size)
 {
 	unsigned int reg, val;
 	char *p = (char *)buf;
 
 	while (p < (buf + size)) {
 		if ((sscanf(p, "%u %x\n", &reg, &val) != 2) ||
-			reg < 0 || reg >= 32)
+		    reg < 0 || reg >= 32)
 			return -EINVAL;
 		p = strchr(p, '\n') + 1;
 	}
@@ -433,55 +451,62 @@ static ssize_t pcap_store_regs(struct device *dev,
 }
 
 static ssize_t pcap_show_adc_coin(struct device *dev,
-			struct device_attribute *attr, char *buf)
+				  struct device_attribute *attr, char *buf)
 {
 	u32 res;
 
 	ezx_pcap_do_general_adc(PCAP_ADC_BANK_0, PCAP_ADC_CH_COIN, &res);
 	return sprintf(buf, "%d\n", res);
 }
+
 static ssize_t pcap_show_adc_battery(struct device *dev,
-			struct device_attribute *attr, char *buf)
+				     struct device_attribute *attr, char *buf)
 {
 	u32 res;
 
 	ezx_pcap_do_general_adc(PCAP_ADC_BANK_0, PCAP_ADC_CH_BATT, &res);
 	return sprintf(buf, "%d\n", res);
 }
+
 static ssize_t pcap_show_adc_bplus(struct device *dev,
-			struct device_attribute *attr, char *buf)
+				   struct device_attribute *attr, char *buf)
 {
 	u32 res;
 
 	ezx_pcap_do_general_adc(PCAP_ADC_BANK_0, PCAP_ADC_CH_BPLUS, &res);
 	return sprintf(buf, "%d\n", res);
 }
+
 static ssize_t pcap_show_adc_mobportb(struct device *dev,
-			struct device_attribute *attr, char *buf)
+				      struct device_attribute *attr, char *buf)
 {
 	u32 res;
 
 	ezx_pcap_do_general_adc(PCAP_ADC_BANK_0, PCAP_ADC_CH_MOBPORTB, &res);
 	return sprintf(buf, "%d\n", res);
 }
+
 static ssize_t pcap_show_adc_temperature(struct device *dev,
-			struct device_attribute *attr, char *buf)
+					 struct device_attribute *attr,
+					 char *buf)
 {
 	u32 res;
 
 	ezx_pcap_do_general_adc(PCAP_ADC_BANK_0, PCAP_ADC_CH_TEMPERATURE, &res);
 	return sprintf(buf, "%d\n", res);
 }
+
 static ssize_t pcap_show_adc_chargerid(struct device *dev,
-			struct device_attribute *attr, char *buf)
+				       struct device_attribute *attr, char *buf)
 {
 	u32 res;
 
 	ezx_pcap_do_general_adc(PCAP_ADC_BANK_0, PCAP_ADC_CH_CHARGER_ID, &res);
 	return sprintf(buf, "%d\n", res);
 }
+
 static ssize_t pcap_show_adc_battcurr(struct device *dev,
-			struct device_attribute *attr, char *buf)
+				      struct device_attribute *attr, char *buf)
 {
 	u32 res[2];
 
@@ -544,6 +569,59 @@ fail1:	device_remove_file(&pcap.spi->dev, &dev_attr_adc_coin);
 ret:	return ret;
 }
 
+static int pcap_bt_toggle_radio(void *data, enum rfkill_state state)
+{
+
+	switch (state) {
+	case RFKILL_STATE_SOFT_BLOCKED:
+		ezx_pcap_set_vreg(V6, V_EN, 0);
+		return 0;
+	case RFKILL_STATE_UNBLOCKED:
+		ezx_pcap_set_vreg(V6, V_EN, 1);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int pcap_bt_getstate(void *data, enum rfkill_state *state)
+{
+	unsigned int val;
+
+	ezx_pcap_read(PCAP_REG_VREG2, &val);
+
+	val &= 2;
+
+
+	if (val)
+		*state = RFKILL_STATE_UNBLOCKED;
+	else
+		*state = RFKILL_STATE_SOFT_BLOCKED;
+	return 0;
+}
+
+static int __devinit pcap_init_rfkill(struct pcap_platform_data *pdata)
+{
+	if (pdata->config & PCAP_SECOND_PORT)
+		return -ENODEV;
+
+	pcap.rf_kill = rfkill_allocate(&pcap.spi->dev, RFKILL_TYPE_BLUETOOTH);
+	if (!pcap.rf_kill)
+		return -ENOMEM;
+
+	snprintf(pcap.rf_kill_name, sizeof(pcap.rf_kill_name),
+		 "pcap_bt:rfkill");
+	pcap.rf_kill->name = pcap.rf_kill_name;
+	pcap.rf_kill->data = &pcap;
+	pcap.rf_kill->toggle_radio = pcap_bt_toggle_radio;
+	pcap.rf_kill->get_state = pcap_bt_getstate;
+	pcap.rf_kill->state = RFKILL_STATE_SOFT_BLOCKED;
+	pcap.rf_kill->user_claim_unsupported = 1;
+	rfkill_register(pcap.rf_kill);
+
+	return 0;
+}
+
 static int __devexit ezx_pcap_remove(struct spi_device *spi)
 {
 	struct pcap_platform_data *pdata = spi->dev.platform_data;
@@ -553,6 +631,10 @@ static int __devexit ezx_pcap_remove(struct spi_device *spi)
 	ezx_pcap_unregister_event(PCAP_MASK_ALL_INTERRUPT);
 	free_irq(pdata->irq, NULL);
 	pcap.spi = NULL;
+	if (pcap.rf_kill) {
+		rfkill_unregister(pcap.rf_kill);
+		pcap.rf_kill = NULL;
+	}
 
 	return 0;
 }
@@ -605,7 +687,7 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi)
 
 	/* register irq for pcap */
 	ret = request_irq(pdata->irq, pcap_irq_handler, IRQF_DISABLED,
-		"PCAP", NULL);
+			  "PCAP", NULL);
 	if (ret) {
 		dev_err(&spi->dev, "cant request IRQ\n");
 		goto wq_destroy;
@@ -614,8 +696,9 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi)
 	set_irq_wake(pdata->irq, 1);
 
 	ezx_pcap_register_event((pdata->config & PCAP_SECOND_PORT) ?
-			PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE,
-			ezx_pcap_adc_event, NULL, "ADC");
+				PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE,
+				ezx_pcap_adc_event, NULL, "ADC");
+	pcap_init_rfkill(pdata);
 	return 0;
 
 wq_destroy:
@@ -627,12 +710,12 @@ ret:
 }
 
 static struct spi_driver ezxpcap_driver = {
-	.probe  = ezx_pcap_probe,
+	.probe = ezx_pcap_probe,
 	.remove = __devexit_p(ezx_pcap_remove),
 	.driver = {
-		.name   = "ezx-pcap",
-		.owner  = THIS_MODULE,
-	},
+		   .name = "ezx-pcap",
+		   .owner = THIS_MODULE,
+		   },
 };
 
 static int __init ezx_pcap_init(void)
-- 
tg: (807ba06..) ezx/rfkill (depends on: local/power)
