staging/bluetooth: Add hci_h4p driver
Add hci_h4p bluetooth driver to staging tree. This device is used for example on Nokia N900 cell phone. Signed-off-by: Pali Rohár <pali.rohar@gmail.com> Signed-off-by: Pavel Machek <pavel@ucw.cz> Thanks-to: Sebastian Reichel <sre@debian.org> Thanks-to: Joe Perches <joe@perches.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
					parent
					
						
							
								be973fcd81
							
						
					
				
			
			
				commit
				
					
						91eef3e2fe
					
				
			
		
					 13 changed files with 2430 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -148,4 +148,6 @@ source "drivers/staging/dgap/Kconfig"
 | 
			
		|||
 | 
			
		||||
source "drivers/staging/gs_fpgaboot/Kconfig"
 | 
			
		||||
 | 
			
		||||
source "drivers/staging/nokia_h4p/Kconfig"
 | 
			
		||||
 | 
			
		||||
endif # STAGING
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,3 +66,4 @@ obj-$(CONFIG_DGNC)			+= dgnc/
 | 
			
		|||
obj-$(CONFIG_DGAP)			+= dgap/
 | 
			
		||||
obj-$(CONFIG_MTD_SPINAND_MT29F)	+= mt29f_spinand/
 | 
			
		||||
obj-$(CONFIG_GS_FPGABOOT)	+= gs_fpgaboot/
 | 
			
		||||
obj-$(CONFIG_BT_NOKIA_H4P)	+= nokia_h4p/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								drivers/staging/nokia_h4p/Kconfig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								drivers/staging/nokia_h4p/Kconfig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
config BT_NOKIA_H4P
 | 
			
		||||
	tristate "HCI driver with H4 Nokia extensions"
 | 
			
		||||
	depends on BT && ARCH_OMAP
 | 
			
		||||
	help
 | 
			
		||||
	  Bluetooth HCI driver with H4 extensions.  This driver provides
 | 
			
		||||
	  support for H4+ Bluetooth chip with vendor-specific H4 extensions.
 | 
			
		||||
 | 
			
		||||
	  Say Y here to compile support for h4 extended devices into the kernel
 | 
			
		||||
	  or say M to compile it as module (btnokia_h4p).
 | 
			
		||||
							
								
								
									
										6
									
								
								drivers/staging/nokia_h4p/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								drivers/staging/nokia_h4p/Makefile
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
 | 
			
		||||
obj-$(CONFIG_BT_NOKIA_H4P)		+= btnokia_h4p.o
 | 
			
		||||
btnokia_h4p-objs := nokia_core.o nokia_fw.o nokia_uart.o nokia_fw-csr.o \
 | 
			
		||||
		nokia_fw-bcm.o nokia_fw-ti1273.o
 | 
			
		||||
 | 
			
		||||
ccflags-y += -D__CHECK_ENDIAN__
 | 
			
		||||
							
								
								
									
										140
									
								
								drivers/staging/nokia_h4p/TODO
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								drivers/staging/nokia_h4p/TODO
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,140 @@
 | 
			
		|||
Few attempts to submission have been made, last review comments were received in
 | 
			
		||||
 | 
			
		||||
Date: Wed, 15 Jan 2014 19:01:51 -0800
 | 
			
		||||
From: Marcel Holtmann <marcel@holtmann.org>
 | 
			
		||||
Subject: Re: [PATCH v6] Bluetooth: Add hci_h4p driver
 | 
			
		||||
 | 
			
		||||
Some code refactoring is still needed.
 | 
			
		||||
 | 
			
		||||
TODO:
 | 
			
		||||
 | 
			
		||||
> +++ b/drivers/bluetooth/hci_h4p.h
 | 
			
		||||
 | 
			
		||||
can we please get the naming straight. File names do not start with
 | 
			
		||||
hci_ anymore. We moved away from it since that term is too generic.
 | 
			
		||||
 | 
			
		||||
> +#define FW_NAME_TI1271_LE    "ti1273_le.bin"
 | 
			
		||||
> +#define FW_NAME_TI1271               "ti1273.bin"
 | 
			
		||||
> +#define FW_NAME_BCM2048              "bcmfw.bin"
 | 
			
		||||
> +#define FW_NAME_CSR          "bc4fw.bin"
 | 
			
		||||
 | 
			
		||||
We do these have to be global in a header file. This should be
 | 
			
		||||
confined to the specific firmware part.
 | 
			
		||||
 | 
			
		||||
> +struct hci_h4p_info {
 | 
			
		||||
 | 
			
		||||
Can we please get rid of the hci_ prefix for everything. Copying from
 | 
			
		||||
drivers that are over 10 years old is not a good idea. Please look at
 | 
			
		||||
recent ones.
 | 
			
		||||
 | 
			
		||||
> +     struct timer_list lazy_release;
 | 
			
		||||
 | 
			
		||||
Timer? Not delayed work?
 | 
			
		||||
 | 
			
		||||
> +void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val);
 | 
			
		||||
> +u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset);
 | 
			
		||||
> +void hci_h4p_set_rts(struct hci_h4p_info *info, int active);
 | 
			
		||||
> +int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, int timeout_ms);
 | 
			
		||||
> +void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
 | 
			
		||||
> +void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
 | 
			
		||||
> +void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed);
 | 
			
		||||
> +int hci_h4p_reset_uart(struct hci_h4p_info *info);
 | 
			
		||||
> +void hci_h4p_init_uart(struct hci_h4p_info *info);
 | 
			
		||||
> +void hci_h4p_enable_tx(struct hci_h4p_info *info);
 | 
			
		||||
> +void hci_h4p_store_regs(struct hci_h4p_info *info);
 | 
			
		||||
> +void hci_h4p_restore_regs(struct hci_h4p_info *info);
 | 
			
		||||
> +void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable);
 | 
			
		||||
 | 
			
		||||
These are a lot of public functions. Are they all really needed or can
 | 
			
		||||
the code be done smart.
 | 
			
		||||
 | 
			
		||||
> +static ssize_t hci_h4p_store_bdaddr(struct device *dev,
 | 
			
		||||
> +                                 struct device_attribute *attr,
 | 
			
		||||
> +                                 const char *buf, size_t count)
 | 
			
		||||
> +{
 | 
			
		||||
> +     struct hci_h4p_info *info = dev_get_drvdata(dev);
 | 
			
		||||
 | 
			
		||||
Since none of these devices can function without having a valid
 | 
			
		||||
address, the way this should work is that we should not register the
 | 
			
		||||
HCI device when probing the platform device.
 | 
			
		||||
    
 | 
			
		||||
The HCI device should be registered once a valid address has been
 | 
			
		||||
written into the sysfs file. I do not want to play the tricks with
 | 
			
		||||
bringing up the device without a valid address.
 | 
			
		||||
 | 
			
		||||
> +     hdev->close = hci_h4p_hci_close;
 | 
			
		||||
> +     hdev->flush = hci_h4p_hci_flush;
 | 
			
		||||
> +     hdev->send = hci_h4p_hci_send_frame;
 | 
			
		||||
    
 | 
			
		||||
It needs to use hdev->setup to load the firmware. I assume the
 | 
			
		||||
firmware only needs to be loaded once. That is exactly what
 | 
			
		||||
hdev->setup does. It gets executed once.
 | 
			
		||||
    
 | 
			
		||||
> +     set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 | 
			
		||||
 | 
			
		||||
Is this quirk really needed? Normally only Bluetooth 1.1 and early
 | 
			
		||||
devices qualify for it.
 | 
			
		||||
 | 
			
		||||
> +static int hci_h4p_bcm_set_bdaddr(struct hci_h4p_info *info, struct sk_buff *skb)
 | 
			
		||||
> +{
 | 
			
		||||
> +     int i;
 | 
			
		||||
> +     static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
 | 
			
		||||
> +     int not_valid;
 | 
			
		||||
 | 
			
		||||
Has this actually been confirmed that we can just randomly set an
 | 
			
		||||
address out of the Nokia range. I do not think so. This is a pretty
 | 
			
		||||
bad idea.
 | 
			
		||||
 | 
			
		||||
I have no interest in merging a driver with such a hack.
 | 
			
		||||
 | 
			
		||||
> +     not_valid = 1;
 | 
			
		||||
> +     for (i = 0; i < 6; i++) {
 | 
			
		||||
> +             if (info->bd_addr[i] != 0x00) {
 | 
			
		||||
> +                     not_valid = 0;
 | 
			
		||||
> +                     break;
 | 
			
		||||
> +             }   
 | 
			
		||||
> +     }
 | 
			
		||||
 | 
			
		||||
Anybody every heard of memcmp or bacmp and BDADDR_ANY?
 | 
			
		||||
 | 
			
		||||
> +             if (not_valid) {
 | 
			
		||||
> +                     dev_info(info->dev, "Valid bluetooth address not found,"
 | 
			
		||||
> +                                     " setting some random\n");
 | 
			
		||||
> +                     /* When address is not valid, use some random */
 | 
			
		||||
> +                     memcpy(info->bd_addr, nokia_oui, 3);
 | 
			
		||||
> +                     get_random_bytes(info->bd_addr + 3, 3);
 | 
			
		||||
> +             }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
And why does every single chip firmware does this differently. Seriously, this is a mess.
 | 
			
		||||
 | 
			
		||||
> +void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
 | 
			
		||||
> +{
 | 
			
		||||
> +     switch (info->man_id) {
 | 
			
		||||
> +     case H4P_ID_CSR:
 | 
			
		||||
> +             hci_h4p_bc4_parse_fw_event(info, skb);
 | 
			
		||||
> +             break;
 | 
			
		||||
...
 | 
			
		||||
> +}
 | 
			
		||||
 | 
			
		||||
We have proper HCI sync command handling in recent kernels. I really
 | 
			
		||||
do not know why this is hand coded these days. Check how the Intel
 | 
			
		||||
firmware loading inside btusb.c does it.
 | 
			
		||||
 | 
			
		||||
> +inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
 | 
			
		||||
> +{ 
 | 
			
		||||
> +     return __raw_readb(info->uart_base + (offset << 2));
 | 
			
		||||
> +}
 | 
			
		||||
 | 
			
		||||
Inline in a *.c file for a non-static function. Makes no sense to me.
 | 
			
		||||
 | 
			
		||||
> +/**
 | 
			
		||||
> + * struct hci_h4p_platform data - hci_h4p Platform data structure
 | 
			
		||||
> + */
 | 
			
		||||
> +struct hci_h4p_platform_data {
 | 
			
		||||
 | 
			
		||||
please have a proper name here. For example
 | 
			
		||||
btnokia_h4p_platform_data.
 | 
			
		||||
 | 
			
		||||
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc:
 | 
			
		||||
Pavel Machek <pavel@ucw.cz>
 | 
			
		||||
							
								
								
									
										228
									
								
								drivers/staging/nokia_h4p/hci_h4p.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								drivers/staging/nokia_h4p/hci_h4p.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,228 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of Nokia H4P bluetooth driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2005-2008 Nokia Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License
 | 
			
		||||
 * version 2 as published by the Free Software Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DRIVERS_BLUETOOTH_HCI_H4P_H
 | 
			
		||||
#define __DRIVERS_BLUETOOTH_HCI_H4P_H
 | 
			
		||||
 | 
			
		||||
#include <net/bluetooth/bluetooth.h>
 | 
			
		||||
#include <net/bluetooth/hci_core.h>
 | 
			
		||||
#include <net/bluetooth/hci.h>
 | 
			
		||||
 | 
			
		||||
#define FW_NAME_TI1271_PRELE	"ti1273_prele.bin"
 | 
			
		||||
#define FW_NAME_TI1271_LE	"ti1273_le.bin"
 | 
			
		||||
#define FW_NAME_TI1271		"ti1273.bin"
 | 
			
		||||
#define FW_NAME_BCM2048		"bcmfw.bin"
 | 
			
		||||
#define FW_NAME_CSR		"bc4fw.bin"
 | 
			
		||||
 | 
			
		||||
#define UART_SYSC_OMAP_RESET	0x03
 | 
			
		||||
#define UART_SYSS_RESETDONE	0x01
 | 
			
		||||
#define UART_OMAP_SCR_EMPTY_THR	0x08
 | 
			
		||||
#define UART_OMAP_SCR_WAKEUP	0x10
 | 
			
		||||
#define UART_OMAP_SSR_WAKEUP	0x02
 | 
			
		||||
#define UART_OMAP_SSR_TXFULL	0x01
 | 
			
		||||
 | 
			
		||||
#define UART_OMAP_SYSC_IDLEMODE		0x03
 | 
			
		||||
#define UART_OMAP_SYSC_IDLEMASK		(3 << UART_OMAP_SYSC_IDLEMODE)
 | 
			
		||||
 | 
			
		||||
#define UART_OMAP_SYSC_FORCE_IDLE	(0 << UART_OMAP_SYSC_IDLEMODE)
 | 
			
		||||
#define UART_OMAP_SYSC_NO_IDLE		(1 << UART_OMAP_SYSC_IDLEMODE)
 | 
			
		||||
#define UART_OMAP_SYSC_SMART_IDLE	(2 << UART_OMAP_SYSC_IDLEMODE)
 | 
			
		||||
 | 
			
		||||
#define H4P_TRANSFER_MODE		1
 | 
			
		||||
#define H4P_SCHED_TRANSFER_MODE		2
 | 
			
		||||
#define H4P_ACTIVE_MODE			3
 | 
			
		||||
 | 
			
		||||
struct hci_h4p_info {
 | 
			
		||||
	struct timer_list lazy_release;
 | 
			
		||||
	struct hci_dev *hdev;
 | 
			
		||||
	spinlock_t lock;
 | 
			
		||||
 | 
			
		||||
	void __iomem *uart_base;
 | 
			
		||||
	unsigned long uart_phys_base;
 | 
			
		||||
	int irq;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	u8 chip_type;
 | 
			
		||||
	u8 bt_wakeup_gpio;
 | 
			
		||||
	u8 host_wakeup_gpio;
 | 
			
		||||
	u8 reset_gpio;
 | 
			
		||||
	u8 reset_gpio_shared;
 | 
			
		||||
	u8 bt_sysclk;
 | 
			
		||||
	u8 man_id;
 | 
			
		||||
	u8 ver_id;
 | 
			
		||||
 | 
			
		||||
	struct sk_buff_head fw_queue;
 | 
			
		||||
	struct sk_buff *alive_cmd_skb;
 | 
			
		||||
	struct completion init_completion;
 | 
			
		||||
	struct completion fw_completion;
 | 
			
		||||
	struct completion test_completion;
 | 
			
		||||
	int fw_error;
 | 
			
		||||
	int init_error;
 | 
			
		||||
 | 
			
		||||
	struct sk_buff_head txq;
 | 
			
		||||
 | 
			
		||||
	struct sk_buff *rx_skb;
 | 
			
		||||
	long rx_count;
 | 
			
		||||
	unsigned long rx_state;
 | 
			
		||||
	unsigned long garbage_bytes;
 | 
			
		||||
 | 
			
		||||
	u8 bd_addr[6];
 | 
			
		||||
	struct sk_buff_head *fw_q;
 | 
			
		||||
 | 
			
		||||
	int pm_enabled;
 | 
			
		||||
	int tx_enabled;
 | 
			
		||||
	int autorts;
 | 
			
		||||
	int rx_enabled;
 | 
			
		||||
	unsigned long pm_flags;
 | 
			
		||||
 | 
			
		||||
	int tx_clocks_en;
 | 
			
		||||
	int rx_clocks_en;
 | 
			
		||||
	spinlock_t clocks_lock;
 | 
			
		||||
	struct clk *uart_iclk;
 | 
			
		||||
	struct clk *uart_fclk;
 | 
			
		||||
	atomic_t clk_users;
 | 
			
		||||
	u16 dll;
 | 
			
		||||
	u16 dlh;
 | 
			
		||||
	u16 ier;
 | 
			
		||||
	u16 mdr1;
 | 
			
		||||
	u16 efr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct hci_h4p_radio_hdr {
 | 
			
		||||
	__u8 evt;
 | 
			
		||||
	__u8 dlen;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct hci_h4p_neg_hdr {
 | 
			
		||||
	__u8 dlen;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
#define H4P_NEG_HDR_SIZE 1
 | 
			
		||||
 | 
			
		||||
#define H4P_NEG_REQ	0x00
 | 
			
		||||
#define H4P_NEG_ACK	0x20
 | 
			
		||||
#define H4P_NEG_NAK	0x40
 | 
			
		||||
 | 
			
		||||
#define H4P_PROTO_PKT	0x44
 | 
			
		||||
#define H4P_PROTO_BYTE	0x4c
 | 
			
		||||
 | 
			
		||||
#define H4P_ID_CSR	0x02
 | 
			
		||||
#define H4P_ID_BCM2048	0x04
 | 
			
		||||
#define H4P_ID_TI1271	0x31
 | 
			
		||||
 | 
			
		||||
struct hci_h4p_neg_cmd {
 | 
			
		||||
	__u8	ack;
 | 
			
		||||
	__u16	baud;
 | 
			
		||||
	__u16	unused1;
 | 
			
		||||
	__u8	proto;
 | 
			
		||||
	__u16	sys_clk;
 | 
			
		||||
	__u16	unused2;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct hci_h4p_neg_evt {
 | 
			
		||||
	__u8	ack;
 | 
			
		||||
	__u16	baud;
 | 
			
		||||
	__u16	unused1;
 | 
			
		||||
	__u8	proto;
 | 
			
		||||
	__u16	sys_clk;
 | 
			
		||||
	__u16	unused2;
 | 
			
		||||
	__u8	man_id;
 | 
			
		||||
	__u8	ver_id;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
#define H4P_ALIVE_REQ	0x55
 | 
			
		||||
#define H4P_ALIVE_RESP	0xcc
 | 
			
		||||
 | 
			
		||||
struct hci_h4p_alive_hdr {
 | 
			
		||||
	__u8	dlen;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
#define H4P_ALIVE_HDR_SIZE 1
 | 
			
		||||
 | 
			
		||||
struct hci_h4p_alive_pkt {
 | 
			
		||||
	__u8	mid;
 | 
			
		||||
	__u8	unused;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
#define MAX_BAUD_RATE		921600
 | 
			
		||||
#define BC4_MAX_BAUD_RATE	3692300
 | 
			
		||||
#define UART_CLOCK		48000000
 | 
			
		||||
#define BT_INIT_DIVIDER		320
 | 
			
		||||
#define BT_BAUDRATE_DIVIDER	384000000
 | 
			
		||||
#define BT_SYSCLK_DIV		1000
 | 
			
		||||
#define INIT_SPEED		120000
 | 
			
		||||
 | 
			
		||||
#define H4_TYPE_SIZE		1
 | 
			
		||||
#define H4_RADIO_HDR_SIZE	2
 | 
			
		||||
 | 
			
		||||
/* H4+ packet types */
 | 
			
		||||
#define H4_CMD_PKT		0x01
 | 
			
		||||
#define H4_ACL_PKT		0x02
 | 
			
		||||
#define H4_SCO_PKT		0x03
 | 
			
		||||
#define H4_EVT_PKT		0x04
 | 
			
		||||
#define H4_NEG_PKT		0x06
 | 
			
		||||
#define H4_ALIVE_PKT		0x07
 | 
			
		||||
#define H4_RADIO_PKT		0x08
 | 
			
		||||
 | 
			
		||||
/* TX states */
 | 
			
		||||
#define WAIT_FOR_PKT_TYPE	1
 | 
			
		||||
#define WAIT_FOR_HEADER		2
 | 
			
		||||
#define WAIT_FOR_DATA		3
 | 
			
		||||
 | 
			
		||||
struct hci_fw_event {
 | 
			
		||||
	struct hci_event_hdr hev;
 | 
			
		||||
	struct hci_ev_cmd_complete cmd;
 | 
			
		||||
	u8 status;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
int hci_h4p_send_alive_packet(struct hci_h4p_info *info);
 | 
			
		||||
 | 
			
		||||
void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info,
 | 
			
		||||
				struct sk_buff *skb);
 | 
			
		||||
int hci_h4p_bcm_send_fw(struct hci_h4p_info *info,
 | 
			
		||||
			struct sk_buff_head *fw_queue);
 | 
			
		||||
 | 
			
		||||
void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info,
 | 
			
		||||
				struct sk_buff *skb);
 | 
			
		||||
int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
 | 
			
		||||
			struct sk_buff_head *fw_queue);
 | 
			
		||||
 | 
			
		||||
void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info,
 | 
			
		||||
				    struct sk_buff *skb);
 | 
			
		||||
int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info,
 | 
			
		||||
			    struct sk_buff_head *fw_queue);
 | 
			
		||||
 | 
			
		||||
int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
 | 
			
		||||
int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
 | 
			
		||||
void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb);
 | 
			
		||||
 | 
			
		||||
void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val);
 | 
			
		||||
u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset);
 | 
			
		||||
void hci_h4p_set_rts(struct hci_h4p_info *info, int active);
 | 
			
		||||
int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, int timeout_ms);
 | 
			
		||||
void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
 | 
			
		||||
void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
 | 
			
		||||
void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed);
 | 
			
		||||
int hci_h4p_reset_uart(struct hci_h4p_info *info);
 | 
			
		||||
void hci_h4p_init_uart(struct hci_h4p_info *info);
 | 
			
		||||
void hci_h4p_enable_tx(struct hci_h4p_info *info);
 | 
			
		||||
void hci_h4p_store_regs(struct hci_h4p_info *info);
 | 
			
		||||
void hci_h4p_restore_regs(struct hci_h4p_info *info);
 | 
			
		||||
void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable);
 | 
			
		||||
 | 
			
		||||
#endif /* __DRIVERS_BLUETOOTH_HCI_H4P_H */
 | 
			
		||||
							
								
								
									
										1205
									
								
								drivers/staging/nokia_h4p/nokia_core.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1205
									
								
								drivers/staging/nokia_h4p/nokia_core.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										147
									
								
								drivers/staging/nokia_h4p/nokia_fw-bcm.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								drivers/staging/nokia_h4p/nokia_fw-bcm.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,147 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of Nokia H4P bluetooth driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2005-2008 Nokia Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License
 | 
			
		||||
 * version 2 as published by the Free Software Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/serial_reg.h>
 | 
			
		||||
 | 
			
		||||
#include "hci_h4p.h"
 | 
			
		||||
 | 
			
		||||
static int hci_h4p_bcm_set_bdaddr(struct hci_h4p_info *info, struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
 | 
			
		||||
	int not_valid;
 | 
			
		||||
 | 
			
		||||
	not_valid = 1;
 | 
			
		||||
	for (i = 0; i < 6; i++) {
 | 
			
		||||
		if (info->bd_addr[i] != 0x00) {
 | 
			
		||||
			not_valid = 0;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (not_valid) {
 | 
			
		||||
		dev_info(info->dev, "Valid bluetooth address not found, setting some random\n");
 | 
			
		||||
		/* When address is not valid, use some random but Nokia MAC */
 | 
			
		||||
		memcpy(info->bd_addr, nokia_oui, 3);
 | 
			
		||||
		get_random_bytes(info->bd_addr + 3, 3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 6; i++)
 | 
			
		||||
		skb->data[9 - i] = info->bd_addr[i];
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	struct sk_buff *fw_skb;
 | 
			
		||||
	int err;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	if (skb->data[5] != 0x00) {
 | 
			
		||||
		dev_err(info->dev, "Firmware sending command failed 0x%.2x\n",
 | 
			
		||||
			skb->data[5]);
 | 
			
		||||
		info->fw_error = -EPROTO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kfree_skb(skb);
 | 
			
		||||
 | 
			
		||||
	fw_skb = skb_dequeue(info->fw_q);
 | 
			
		||||
	if (fw_skb == NULL || info->fw_error) {
 | 
			
		||||
		complete(&info->fw_completion);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (fw_skb->data[1] == 0x01 && fw_skb->data[2] == 0xfc && fw_skb->len >= 10) {
 | 
			
		||||
		BT_DBG("Setting bluetooth address");
 | 
			
		||||
		err = hci_h4p_bcm_set_bdaddr(info, fw_skb);
 | 
			
		||||
		if (err < 0) {
 | 
			
		||||
			kfree_skb(fw_skb);
 | 
			
		||||
			info->fw_error = err;
 | 
			
		||||
			complete(&info->fw_completion);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	skb_queue_tail(&info->txq, fw_skb);
 | 
			
		||||
	spin_lock_irqsave(&info->lock, flags);
 | 
			
		||||
	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
 | 
			
		||||
			UART_IER_THRI);
 | 
			
		||||
	spin_unlock_irqrestore(&info->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int hci_h4p_bcm_send_fw(struct hci_h4p_info *info,
 | 
			
		||||
			struct sk_buff_head *fw_queue)
 | 
			
		||||
{
 | 
			
		||||
	struct sk_buff *skb;
 | 
			
		||||
	unsigned long flags, time;
 | 
			
		||||
 | 
			
		||||
	info->fw_error = 0;
 | 
			
		||||
 | 
			
		||||
	BT_DBG("Sending firmware");
 | 
			
		||||
 | 
			
		||||
	time = jiffies;
 | 
			
		||||
 | 
			
		||||
	info->fw_q = fw_queue;
 | 
			
		||||
	skb = skb_dequeue(fw_queue);
 | 
			
		||||
	if (!skb)
 | 
			
		||||
		return -ENODATA;
 | 
			
		||||
 | 
			
		||||
	BT_DBG("Sending commands");
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Disable smart-idle as UART TX interrupts
 | 
			
		||||
	 * are not wake-up capable
 | 
			
		||||
	 */
 | 
			
		||||
	hci_h4p_smart_idle(info, 0);
 | 
			
		||||
 | 
			
		||||
	/* Check if this is bd_address packet */
 | 
			
		||||
	init_completion(&info->fw_completion);
 | 
			
		||||
	skb_queue_tail(&info->txq, skb);
 | 
			
		||||
	spin_lock_irqsave(&info->lock, flags);
 | 
			
		||||
	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
 | 
			
		||||
			UART_IER_THRI);
 | 
			
		||||
	spin_unlock_irqrestore(&info->lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (!wait_for_completion_timeout(&info->fw_completion,
 | 
			
		||||
				msecs_to_jiffies(2000))) {
 | 
			
		||||
		dev_err(info->dev, "No reply to fw command\n");
 | 
			
		||||
		return -ETIMEDOUT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (info->fw_error) {
 | 
			
		||||
		dev_err(info->dev, "FW error\n");
 | 
			
		||||
		return -EPROTO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BT_DBG("Firmware sent in %d msecs",
 | 
			
		||||
		   jiffies_to_msecs(jiffies-time));
 | 
			
		||||
 | 
			
		||||
	hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
 | 
			
		||||
	hci_h4p_set_rts(info, 0);
 | 
			
		||||
	hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
 | 
			
		||||
	hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										150
									
								
								drivers/staging/nokia_h4p/nokia_fw-csr.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								drivers/staging/nokia_h4p/nokia_fw-csr.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,150 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of Nokia H4P bluetooth driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2005-2008 Nokia Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License
 | 
			
		||||
 * version 2 as published by the Free Software Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/serial_reg.h>
 | 
			
		||||
 | 
			
		||||
#include "hci_h4p.h"
 | 
			
		||||
 | 
			
		||||
void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	/* Check if this is fw packet */
 | 
			
		||||
	if (skb->data[0] != 0xff) {
 | 
			
		||||
		hci_recv_frame(info->hdev, skb);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (skb->data[11] || skb->data[12]) {
 | 
			
		||||
		dev_err(info->dev, "Firmware sending command failed\n");
 | 
			
		||||
		info->fw_error = -EPROTO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kfree_skb(skb);
 | 
			
		||||
	complete(&info->fw_completion);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
 | 
			
		||||
			struct sk_buff_head *fw_queue)
 | 
			
		||||
{
 | 
			
		||||
	static const u8 nokia_oui[3] = {0x00, 0x19, 0x4F};
 | 
			
		||||
	struct sk_buff *skb;
 | 
			
		||||
	unsigned int offset;
 | 
			
		||||
	int retries, count, i, not_valid;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	info->fw_error = 0;
 | 
			
		||||
 | 
			
		||||
	BT_DBG("Sending firmware");
 | 
			
		||||
	skb = skb_dequeue(fw_queue);
 | 
			
		||||
 | 
			
		||||
	if (!skb)
 | 
			
		||||
		return -ENOMSG;
 | 
			
		||||
 | 
			
		||||
	/* Check if this is bd_address packet */
 | 
			
		||||
	if (skb->data[15] == 0x01 && skb->data[16] == 0x00) {
 | 
			
		||||
		offset = 21;
 | 
			
		||||
		skb->data[offset + 1] = 0x00;
 | 
			
		||||
		skb->data[offset + 5] = 0x00;
 | 
			
		||||
 | 
			
		||||
		not_valid = 1;
 | 
			
		||||
		for (i = 0; i < 6; i++) {
 | 
			
		||||
			if (info->bd_addr[i] != 0x00) {
 | 
			
		||||
				not_valid = 0;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (not_valid) {
 | 
			
		||||
			dev_info(info->dev, "Valid bluetooth address not found,"
 | 
			
		||||
					" setting some random\n");
 | 
			
		||||
			/* When address is not valid, use some random */
 | 
			
		||||
			memcpy(info->bd_addr, nokia_oui, 3);
 | 
			
		||||
			get_random_bytes(info->bd_addr + 3, 3);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		skb->data[offset + 7] = info->bd_addr[0];
 | 
			
		||||
		skb->data[offset + 6] = info->bd_addr[1];
 | 
			
		||||
		skb->data[offset + 4] = info->bd_addr[2];
 | 
			
		||||
		skb->data[offset + 0] = info->bd_addr[3];
 | 
			
		||||
		skb->data[offset + 3] = info->bd_addr[4];
 | 
			
		||||
		skb->data[offset + 2] = info->bd_addr[5];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (count = 1; ; count++) {
 | 
			
		||||
		BT_DBG("Sending firmware command %d", count);
 | 
			
		||||
		init_completion(&info->fw_completion);
 | 
			
		||||
		skb_queue_tail(&info->txq, skb);
 | 
			
		||||
		spin_lock_irqsave(&info->lock, flags);
 | 
			
		||||
		hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
 | 
			
		||||
							 UART_IER_THRI);
 | 
			
		||||
		spin_unlock_irqrestore(&info->lock, flags);
 | 
			
		||||
 | 
			
		||||
		skb = skb_dequeue(fw_queue);
 | 
			
		||||
		if (!skb)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		if (!wait_for_completion_timeout(&info->fw_completion,
 | 
			
		||||
						 msecs_to_jiffies(1000))) {
 | 
			
		||||
			dev_err(info->dev, "No reply to fw command\n");
 | 
			
		||||
			return -ETIMEDOUT;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (info->fw_error) {
 | 
			
		||||
			dev_err(info->dev, "FW error\n");
 | 
			
		||||
			return -EPROTO;
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/* Wait for chip warm reset */
 | 
			
		||||
	retries = 100;
 | 
			
		||||
	while ((!skb_queue_empty(&info->txq) ||
 | 
			
		||||
	       !(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) &&
 | 
			
		||||
	       retries--) {
 | 
			
		||||
		msleep(10);
 | 
			
		||||
	}
 | 
			
		||||
	if (!retries) {
 | 
			
		||||
		dev_err(info->dev, "Transmitter not empty\n");
 | 
			
		||||
		return -ETIMEDOUT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
 | 
			
		||||
 | 
			
		||||
	if (hci_h4p_wait_for_cts(info, 1, 100)) {
 | 
			
		||||
		dev_err(info->dev, "cts didn't deassert after final speed\n");
 | 
			
		||||
		return -ETIMEDOUT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	retries = 100;
 | 
			
		||||
	do {
 | 
			
		||||
		init_completion(&info->init_completion);
 | 
			
		||||
		hci_h4p_send_alive_packet(info);
 | 
			
		||||
		retries--;
 | 
			
		||||
	} while (!wait_for_completion_timeout(&info->init_completion, 100) &&
 | 
			
		||||
		 retries > 0);
 | 
			
		||||
 | 
			
		||||
	if (!retries) {
 | 
			
		||||
		dev_err(info->dev, "No alive reply after speed change\n");
 | 
			
		||||
		return -ETIMEDOUT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										110
									
								
								drivers/staging/nokia_h4p/nokia_fw-ti1273.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								drivers/staging/nokia_h4p/nokia_fw-ti1273.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,110 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of Nokia H4P bluetooth driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2009 Nokia Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License
 | 
			
		||||
 * version 2 as published by the Free Software Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/serial_reg.h>
 | 
			
		||||
 | 
			
		||||
#include "hci_h4p.h"
 | 
			
		||||
 | 
			
		||||
static struct sk_buff_head *fw_q;
 | 
			
		||||
 | 
			
		||||
void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info,
 | 
			
		||||
			struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	struct sk_buff *fw_skb;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	if (skb->data[5] != 0x00) {
 | 
			
		||||
		dev_err(info->dev, "Firmware sending command failed 0x%.2x\n",
 | 
			
		||||
			skb->data[5]);
 | 
			
		||||
		info->fw_error = -EPROTO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kfree_skb(skb);
 | 
			
		||||
 | 
			
		||||
	fw_skb = skb_dequeue(fw_q);
 | 
			
		||||
	if (fw_skb == NULL || info->fw_error) {
 | 
			
		||||
		complete(&info->fw_completion);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	skb_queue_tail(&info->txq, fw_skb);
 | 
			
		||||
	spin_lock_irqsave(&info->lock, flags);
 | 
			
		||||
	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
 | 
			
		||||
			UART_IER_THRI);
 | 
			
		||||
	spin_unlock_irqrestore(&info->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info,
 | 
			
		||||
			struct sk_buff_head *fw_queue)
 | 
			
		||||
{
 | 
			
		||||
	struct sk_buff *skb;
 | 
			
		||||
	unsigned long flags, time;
 | 
			
		||||
 | 
			
		||||
	info->fw_error = 0;
 | 
			
		||||
 | 
			
		||||
	BT_DBG("Sending firmware");
 | 
			
		||||
 | 
			
		||||
	time = jiffies;
 | 
			
		||||
 | 
			
		||||
	fw_q = fw_queue;
 | 
			
		||||
	skb = skb_dequeue(fw_queue);
 | 
			
		||||
	if (!skb)
 | 
			
		||||
		return -ENODATA;
 | 
			
		||||
 | 
			
		||||
	BT_DBG("Sending commands");
 | 
			
		||||
	/* Check if this is bd_address packet */
 | 
			
		||||
	init_completion(&info->fw_completion);
 | 
			
		||||
	hci_h4p_smart_idle(info, 0);
 | 
			
		||||
	skb_queue_tail(&info->txq, skb);
 | 
			
		||||
	spin_lock_irqsave(&info->lock, flags);
 | 
			
		||||
	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
 | 
			
		||||
			UART_IER_THRI);
 | 
			
		||||
	spin_unlock_irqrestore(&info->lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (!wait_for_completion_timeout(&info->fw_completion,
 | 
			
		||||
				msecs_to_jiffies(2000))) {
 | 
			
		||||
		dev_err(info->dev, "No reply to fw command\n");
 | 
			
		||||
		return -ETIMEDOUT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (info->fw_error) {
 | 
			
		||||
		dev_err(info->dev, "FW error\n");
 | 
			
		||||
		return -EPROTO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BT_DBG("Firmware sent in %d msecs",
 | 
			
		||||
		   jiffies_to_msecs(jiffies-time));
 | 
			
		||||
 | 
			
		||||
	hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
 | 
			
		||||
	hci_h4p_set_rts(info, 0);
 | 
			
		||||
	hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
 | 
			
		||||
	if (hci_h4p_wait_for_cts(info, 1, 100)) {
 | 
			
		||||
		dev_err(info->dev,
 | 
			
		||||
			"cts didn't go down after final speed change\n");
 | 
			
		||||
		return -ETIMEDOUT;
 | 
			
		||||
	}
 | 
			
		||||
	hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										195
									
								
								drivers/staging/nokia_h4p/nokia_fw.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								drivers/staging/nokia_h4p/nokia_fw.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,195 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of hci_h4p bluetooth driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2005, 2006 Nokia Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * Contact: Ville Tervo <ville.tervo@nokia.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License
 | 
			
		||||
 * version 2 as published by the Free Software Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
#include <linux/firmware.h>
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
 | 
			
		||||
#include <net/bluetooth/bluetooth.h>
 | 
			
		||||
 | 
			
		||||
#include "hci_h4p.h"
 | 
			
		||||
 | 
			
		||||
static int fw_pos;
 | 
			
		||||
 | 
			
		||||
/* Firmware handling */
 | 
			
		||||
static int hci_h4p_open_firmware(struct hci_h4p_info *info,
 | 
			
		||||
				 const struct firmware **fw_entry)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	fw_pos = 0;
 | 
			
		||||
	BT_DBG("Opening firmware man_id 0x%.2x ver_id 0x%.2x",
 | 
			
		||||
			info->man_id, info->ver_id);
 | 
			
		||||
	switch (info->man_id) {
 | 
			
		||||
	case H4P_ID_TI1271:
 | 
			
		||||
		switch (info->ver_id) {
 | 
			
		||||
		case 0xe1:
 | 
			
		||||
			err = request_firmware(fw_entry, FW_NAME_TI1271_PRELE,
 | 
			
		||||
						info->dev);
 | 
			
		||||
			break;
 | 
			
		||||
		case 0xd1:
 | 
			
		||||
		case 0xf1:
 | 
			
		||||
			err = request_firmware(fw_entry, FW_NAME_TI1271_LE,
 | 
			
		||||
						info->dev);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			err = request_firmware(fw_entry, FW_NAME_TI1271,
 | 
			
		||||
						info->dev);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case H4P_ID_CSR:
 | 
			
		||||
		err = request_firmware(fw_entry, FW_NAME_CSR, info->dev);
 | 
			
		||||
		break;
 | 
			
		||||
	case H4P_ID_BCM2048:
 | 
			
		||||
		err = request_firmware(fw_entry, FW_NAME_BCM2048, info->dev);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		dev_err(info->dev, "Invalid chip type\n");
 | 
			
		||||
		*fw_entry = NULL;
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void hci_h4p_close_firmware(const struct firmware *fw_entry)
 | 
			
		||||
{
 | 
			
		||||
	release_firmware(fw_entry);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Read fw. Return length of the command. If no more commands in
 | 
			
		||||
 * fw 0 is returned. In error case return value is negative.
 | 
			
		||||
 */
 | 
			
		||||
static int hci_h4p_read_fw_cmd(struct hci_h4p_info *info, struct sk_buff **skb,
 | 
			
		||||
			       const struct firmware *fw_entry, gfp_t how)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int cmd_len;
 | 
			
		||||
 | 
			
		||||
	if (fw_pos >= fw_entry->size)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (fw_pos + 2 > fw_entry->size) {
 | 
			
		||||
		dev_err(info->dev, "Corrupted firmware image 1\n");
 | 
			
		||||
		return -EMSGSIZE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd_len = fw_entry->data[fw_pos++];
 | 
			
		||||
	cmd_len += fw_entry->data[fw_pos++] << 8;
 | 
			
		||||
	if (cmd_len == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (fw_pos + cmd_len > fw_entry->size) {
 | 
			
		||||
		dev_err(info->dev, "Corrupted firmware image 2\n");
 | 
			
		||||
		return -EMSGSIZE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*skb = bt_skb_alloc(cmd_len, how);
 | 
			
		||||
	if (!*skb) {
 | 
			
		||||
		dev_err(info->dev, "Cannot reserve memory for buffer\n");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(skb_put(*skb, cmd_len), &fw_entry->data[fw_pos], cmd_len);
 | 
			
		||||
 | 
			
		||||
	fw_pos += cmd_len;
 | 
			
		||||
 | 
			
		||||
	return (*skb)->len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
 | 
			
		||||
{
 | 
			
		||||
	const struct firmware *fw_entry = NULL;
 | 
			
		||||
	struct sk_buff *skb = NULL;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = hci_h4p_open_firmware(info, &fw_entry);
 | 
			
		||||
	if (err < 0 || !fw_entry)
 | 
			
		||||
		goto err_clean;
 | 
			
		||||
 | 
			
		||||
	while ((err = hci_h4p_read_fw_cmd(info, &skb, fw_entry, GFP_KERNEL))) {
 | 
			
		||||
		if (err < 0 || !skb)
 | 
			
		||||
			goto err_clean;
 | 
			
		||||
 | 
			
		||||
		skb_queue_tail(fw_queue, skb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Chip detection code does neg and alive stuff
 | 
			
		||||
	 * discard two first skbs */
 | 
			
		||||
	skb = skb_dequeue(fw_queue);
 | 
			
		||||
	if (!skb) {
 | 
			
		||||
		err = -EMSGSIZE;
 | 
			
		||||
		goto err_clean;
 | 
			
		||||
	}
 | 
			
		||||
	kfree_skb(skb);
 | 
			
		||||
	skb = skb_dequeue(fw_queue);
 | 
			
		||||
	if (!skb) {
 | 
			
		||||
		err = -EMSGSIZE;
 | 
			
		||||
		goto err_clean;
 | 
			
		||||
	}
 | 
			
		||||
	kfree_skb(skb);
 | 
			
		||||
 | 
			
		||||
err_clean:
 | 
			
		||||
	hci_h4p_close_firmware(fw_entry);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	switch (info->man_id) {
 | 
			
		||||
	case H4P_ID_CSR:
 | 
			
		||||
		err = hci_h4p_bc4_send_fw(info, fw_queue);
 | 
			
		||||
		break;
 | 
			
		||||
	case H4P_ID_TI1271:
 | 
			
		||||
		err = hci_h4p_ti1273_send_fw(info, fw_queue);
 | 
			
		||||
		break;
 | 
			
		||||
	case H4P_ID_BCM2048:
 | 
			
		||||
		err = hci_h4p_bcm_send_fw(info, fw_queue);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		dev_err(info->dev, "Don't know how to send firmware\n");
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	switch (info->man_id) {
 | 
			
		||||
	case H4P_ID_CSR:
 | 
			
		||||
		hci_h4p_bc4_parse_fw_event(info, skb);
 | 
			
		||||
		break;
 | 
			
		||||
	case H4P_ID_TI1271:
 | 
			
		||||
		hci_h4p_ti1273_parse_fw_event(info, skb);
 | 
			
		||||
		break;
 | 
			
		||||
	case H4P_ID_BCM2048:
 | 
			
		||||
		hci_h4p_bcm_parse_fw_event(info, skb);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		dev_err(info->dev, "Don't know how to parse fw event\n");
 | 
			
		||||
		info->fw_error = -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										199
									
								
								drivers/staging/nokia_h4p/nokia_uart.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								drivers/staging/nokia_h4p/nokia_uart.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,199 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of Nokia H4P bluetooth driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2005, 2006 Nokia Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License
 | 
			
		||||
 * version 2 as published by the Free Software Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/serial_reg.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
 | 
			
		||||
#include "hci_h4p.h"
 | 
			
		||||
 | 
			
		||||
inline void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val)
 | 
			
		||||
{
 | 
			
		||||
	__raw_writeb(val, info->uart_base + (offset << 2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
 | 
			
		||||
{
 | 
			
		||||
	return __raw_readb(info->uart_base + (offset << 2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hci_h4p_set_rts(struct hci_h4p_info *info, int active)
 | 
			
		||||
{
 | 
			
		||||
	u8 b;
 | 
			
		||||
 | 
			
		||||
	b = hci_h4p_inb(info, UART_MCR);
 | 
			
		||||
	if (active)
 | 
			
		||||
		b |= UART_MCR_RTS;
 | 
			
		||||
	else
 | 
			
		||||
		b &= ~UART_MCR_RTS;
 | 
			
		||||
	hci_h4p_outb(info, UART_MCR, b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active,
 | 
			
		||||
			 int timeout_ms)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long timeout;
 | 
			
		||||
	int state;
 | 
			
		||||
 | 
			
		||||
	timeout = jiffies + msecs_to_jiffies(timeout_ms);
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		state = hci_h4p_inb(info, UART_MSR) & UART_MSR_CTS;
 | 
			
		||||
		if (active) {
 | 
			
		||||
			if (state)
 | 
			
		||||
				return 0;
 | 
			
		||||
		} else {
 | 
			
		||||
			if (!state)
 | 
			
		||||
				return 0;
 | 
			
		||||
		}
 | 
			
		||||
		if (time_after(jiffies, timeout))
 | 
			
		||||
			return -ETIMEDOUT;
 | 
			
		||||
		msleep(1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
 | 
			
		||||
{
 | 
			
		||||
	u8 lcr, b;
 | 
			
		||||
 | 
			
		||||
	lcr = hci_h4p_inb(info, UART_LCR);
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, 0xbf);
 | 
			
		||||
	b = hci_h4p_inb(info, UART_EFR);
 | 
			
		||||
	if (on)
 | 
			
		||||
		b |= which;
 | 
			
		||||
	else
 | 
			
		||||
		b &= ~which;
 | 
			
		||||
	hci_h4p_outb(info, UART_EFR, b);
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, lcr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&info->lock, flags);
 | 
			
		||||
	__hci_h4p_set_auto_ctsrts(info, on, which);
 | 
			
		||||
	spin_unlock_irqrestore(&info->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int divisor;
 | 
			
		||||
	u8 lcr, mdr1;
 | 
			
		||||
 | 
			
		||||
	BT_DBG("Setting speed %lu", speed);
 | 
			
		||||
 | 
			
		||||
	if (speed >= 460800) {
 | 
			
		||||
		divisor = UART_CLOCK / 13 / speed;
 | 
			
		||||
		mdr1 = 3;
 | 
			
		||||
	} else {
 | 
			
		||||
		divisor = UART_CLOCK / 16 / speed;
 | 
			
		||||
		mdr1 = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Make sure UART mode is disabled */
 | 
			
		||||
	hci_h4p_outb(info, UART_OMAP_MDR1, 7);
 | 
			
		||||
 | 
			
		||||
	lcr = hci_h4p_inb(info, UART_LCR);
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);     /* Set DLAB */
 | 
			
		||||
	hci_h4p_outb(info, UART_DLL, divisor & 0xff);    /* Set speed */
 | 
			
		||||
	hci_h4p_outb(info, UART_DLM, divisor >> 8);
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, lcr);
 | 
			
		||||
 | 
			
		||||
	/* Make sure UART mode is enabled */
 | 
			
		||||
	hci_h4p_outb(info, UART_OMAP_MDR1, mdr1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int hci_h4p_reset_uart(struct hci_h4p_info *info)
 | 
			
		||||
{
 | 
			
		||||
	int count = 0;
 | 
			
		||||
 | 
			
		||||
	/* Reset the UART */
 | 
			
		||||
	hci_h4p_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
 | 
			
		||||
	while (!(hci_h4p_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
 | 
			
		||||
		if (count++ > 100) {
 | 
			
		||||
			dev_err(info->dev, "hci_h4p: UART reset timeout\n");
 | 
			
		||||
			return -ENODEV;
 | 
			
		||||
		}
 | 
			
		||||
		udelay(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hci_h4p_store_regs(struct hci_h4p_info *info)
 | 
			
		||||
{
 | 
			
		||||
	u16 lcr = 0;
 | 
			
		||||
 | 
			
		||||
	lcr = hci_h4p_inb(info, UART_LCR);
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, 0xBF);
 | 
			
		||||
	info->dll = hci_h4p_inb(info, UART_DLL);
 | 
			
		||||
	info->dlh = hci_h4p_inb(info, UART_DLM);
 | 
			
		||||
	info->efr = hci_h4p_inb(info, UART_EFR);
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, lcr);
 | 
			
		||||
	info->mdr1 = hci_h4p_inb(info, UART_OMAP_MDR1);
 | 
			
		||||
	info->ier = hci_h4p_inb(info, UART_IER);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hci_h4p_restore_regs(struct hci_h4p_info *info)
 | 
			
		||||
{
 | 
			
		||||
	u16 lcr = 0;
 | 
			
		||||
 | 
			
		||||
	hci_h4p_init_uart(info);
 | 
			
		||||
 | 
			
		||||
	hci_h4p_outb(info, UART_OMAP_MDR1, 7);
 | 
			
		||||
	lcr = hci_h4p_inb(info, UART_LCR);
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, 0xBF);
 | 
			
		||||
	hci_h4p_outb(info, UART_DLL, info->dll);    /* Set speed */
 | 
			
		||||
	hci_h4p_outb(info, UART_DLM, info->dlh);
 | 
			
		||||
	hci_h4p_outb(info, UART_EFR, info->efr);
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, lcr);
 | 
			
		||||
	hci_h4p_outb(info, UART_OMAP_MDR1, info->mdr1);
 | 
			
		||||
	hci_h4p_outb(info, UART_IER, info->ier);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hci_h4p_init_uart(struct hci_h4p_info *info)
 | 
			
		||||
{
 | 
			
		||||
	u8 mcr, efr;
 | 
			
		||||
 | 
			
		||||
	/* Enable and setup FIFO */
 | 
			
		||||
	hci_h4p_outb(info, UART_OMAP_MDR1, 0x00);
 | 
			
		||||
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, 0xbf);
 | 
			
		||||
	efr = hci_h4p_inb(info, UART_EFR);
 | 
			
		||||
	hci_h4p_outb(info, UART_EFR, UART_EFR_ECB);
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
 | 
			
		||||
	mcr = hci_h4p_inb(info, UART_MCR);
 | 
			
		||||
	hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR);
 | 
			
		||||
	hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO |
 | 
			
		||||
			UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
 | 
			
		||||
			(3 << 6) | (0 << 4));
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, 0xbf);
 | 
			
		||||
	hci_h4p_outb(info, UART_TI752_TLR, 0xed);
 | 
			
		||||
	hci_h4p_outb(info, UART_TI752_TCR, 0xef);
 | 
			
		||||
	hci_h4p_outb(info, UART_EFR, efr);
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
 | 
			
		||||
	hci_h4p_outb(info, UART_MCR, 0x00);
 | 
			
		||||
	hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8);
 | 
			
		||||
	hci_h4p_outb(info, UART_IER, UART_IER_RDI);
 | 
			
		||||
	hci_h4p_outb(info, UART_OMAP_SYSC, (1 << 0) | (1 << 2) | (2 << 3));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								include/linux/platform_data/bt-nokia-h4p.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								include/linux/platform_data/bt-nokia-h4p.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of Nokia H4P bluetooth driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2010 Nokia Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU General Public License
 | 
			
		||||
 * version 2 as published by the Free Software Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct hci_h4p_platform data - hci_h4p Platform data structure
 | 
			
		||||
 */
 | 
			
		||||
struct hci_h4p_platform_data {
 | 
			
		||||
	int chip_type;
 | 
			
		||||
	int bt_sysclk;
 | 
			
		||||
	unsigned int bt_wakeup_gpio;
 | 
			
		||||
	unsigned int host_wakeup_gpio;
 | 
			
		||||
	unsigned int reset_gpio;
 | 
			
		||||
	int reset_gpio_shared;
 | 
			
		||||
	unsigned int uart_irq;
 | 
			
		||||
	phys_addr_t uart_base;
 | 
			
		||||
	const char *uart_iclk;
 | 
			
		||||
	const char *uart_fclk;
 | 
			
		||||
	void (*set_pm_limits)(struct device *dev, bool set);
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue