From patchwork Fri Oct 30 10:00:06 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: jan sebastien X-Patchwork-Id: 56591 X-Patchwork-Delegate: tony@atomide.com Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n9U9xNxQ004404 for ; Fri, 30 Oct 2009 09:59:24 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756806AbZJ3J7Q (ORCPT ); Fri, 30 Oct 2009 05:59:16 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1756796AbZJ3J7Q (ORCPT ); Fri, 30 Oct 2009 05:59:16 -0400 Received: from bear.ext.ti.com ([192.94.94.41]:48038 "EHLO bear.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756781AbZJ3J7I (ORCPT ); Fri, 30 Oct 2009 05:59:08 -0400 Received: from dlep36.itg.ti.com ([157.170.170.91]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id n9U9x9rM011285 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 30 Oct 2009 04:59:09 -0500 Received: from localhost.localdomain (localhost [127.0.0.1]) by dlep36.itg.ti.com (8.13.8/8.13.8) with ESMTP id n9U9wvUu029544; Fri, 30 Oct 2009 04:59:07 -0500 (CDT) From: Sebastien Jan To: linux-omap@vger.kernel.org Cc: Sebastien Jan , Andras Domokos Subject: [RFC PATCH 7/9] HSI: character driver low level interface Date: Fri, 30 Oct 2009 11:00:06 +0100 Message-Id: <1256896808-20152-8-git-send-email-s-jan@ti.com> X-Mailer: git-send-email 1.6.0.4 In-Reply-To: <1256896808-20152-1-git-send-email-s-jan@ti.com> References: <1256896808-20152-1-git-send-email-s-jan@ti.com> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org diff --git a/drivers/hsi/hsi-if.c b/drivers/hsi/hsi-if.c new file mode 100644 index 0000000..2c9ba0c --- /dev/null +++ b/drivers/hsi/hsi-if.c @@ -0,0 +1,642 @@ +/* + * hsi-if.c + * + * Part of the HSI character driver, implements the HSI interface. + * + * Copyright (C) 2009 Nokia Corporation. All rights reserved. + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Author: Andras Domokos + * Author: Sebastien JAN + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "hsi-char.h" +#include "hsi-if.h" + +#define HSI_CHANNEL_STATE_UNAVAIL (1 << 0) +#define HSI_CHANNEL_STATE_READING (1 << 1) +#define HSI_CHANNEL_STATE_WRITING (1 << 2) + +#define PORT1 0 +#define PORT2 1 + +#define RXCONV(dst, src) \ + do { \ + (dst)->mode = (src)->mode; \ + (dst)->flow = (src)->flow; \ + (dst)->frame_size = (src)->frame_size; \ + (dst)->channels = (src)->channels; \ + (dst)->divisor = (src)->divisor; \ + } while (0) + +#define TXCONV(dst, src) \ + do { \ + (dst)->mode = (src)->mode; \ + (dst)->flow = (src)->flow; \ + (dst)->frame_size = (src)->frame_size; \ + (dst)->channels = (src)->channels; \ + (dst)->divisor = (src)->divisor; \ + (dst)->arb_mode = (src)->arb_mode; \ + } while (0) + +struct if_hsi_channel { + struct hsi_device *dev; + unsigned int channel_id; + u32 *tx_data; + unsigned int tx_count; + u32 *rx_data; + unsigned int rx_count; + unsigned int opened; + unsigned int state; + spinlock_t lock; /* Serializes access to channel data */ +}; + +struct if_hsi_iface { + struct if_hsi_channel channels[HSI_MAX_CHAR_DEVS]; + int bootstrap; + unsigned long init_chan_map; + spinlock_t lock; /* Serializes access to HSI functional interface */ +}; + +static void if_hsi_port_event(struct hsi_device *dev, unsigned int event, + void *arg); +static int __devinit if_hsi_probe(struct hsi_device *dev); +static int __devexit if_hsi_remove(struct hsi_device *dev); + +static struct hsi_device_driver if_hsi_char_driver = { + .ctrl_mask = ANY_HSI_CONTROLLER, + .probe = if_hsi_probe, + .remove = __devexit_p(if_hsi_remove), + .driver = { + .name = "hsi_char" + }, +}; + +static struct if_hsi_iface hsi_iface; + +static int if_hsi_read_on(int ch, u32 *data, unsigned int count) +{ + struct if_hsi_channel *channel; + int ret; + + channel = &hsi_iface.channels[ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + + spin_lock(&channel->lock); + if (channel->state & HSI_CHANNEL_STATE_READING) { + pr_err("Read still pending on channel %d\n", ch); + spin_unlock(&channel->lock); + return -EBUSY; + } + channel->state |= HSI_CHANNEL_STATE_READING; + channel->rx_data = data; + channel->rx_count = count; + spin_unlock(&channel->lock); + + ret = hsi_read(channel->dev, data, count/4); + dev_dbg(&channel->dev->device, "%s, ch = %d, ret = %d\n", __func__, ch, + ret); + + return ret; +} + +static void if_hsi_read_done(struct hsi_device *dev, unsigned int size) +{ + struct if_hsi_channel *channel; + struct hsi_event ev; + + channel = &hsi_iface.channels[dev->n_ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, dev->n_ch); + spin_lock(&channel->lock); + channel->state &= ~HSI_CHANNEL_STATE_READING; + ev.event = HSI_EV_IN; + ev.data = channel->rx_data; + ev.count = size; + spin_unlock(&channel->lock); + if_notify(dev->n_ch, &ev); +} + +int if_hsi_read(int ch, u32 *data, unsigned int count) +{ + int ret = 0; + struct if_hsi_channel *channel; + channel = &hsi_iface.channels[ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + spin_lock_bh(&hsi_iface.lock); + ret = if_hsi_read_on(ch, data, count); + spin_unlock_bh(&hsi_iface.lock); + return ret; +} + +int if_hsi_poll(int ch) +{ + struct if_hsi_channel *channel; + int ret = 0; + channel = &hsi_iface.channels[ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + spin_lock_bh(&hsi_iface.lock); + ret = hsi_poll(channel->dev); + spin_unlock_bh(&hsi_iface.lock); + return ret; +} + +static int if_hsi_write_on(int ch, u32 *address, unsigned int count) +{ + struct if_hsi_channel *channel; + int ret; + + channel = &hsi_iface.channels[ch]; + + spin_lock(&channel->lock); + if (channel->state & HSI_CHANNEL_STATE_WRITING) { + pr_err("Write still pending on channel %d\n", ch); + spin_unlock(&channel->lock); + return -EBUSY; + } + + channel->tx_data = address; + channel->tx_count = count; + channel->state |= HSI_CHANNEL_STATE_WRITING; + spin_unlock(&channel->lock); + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + ret = hsi_write(channel->dev, address, count/4); + return ret; +} + +static void if_hsi_write_done(struct hsi_device *dev, unsigned int size) +{ + struct if_hsi_channel *channel; + struct hsi_event ev; + + channel = &hsi_iface.channels[dev->n_ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, dev->n_ch); + + spin_lock(&channel->lock); + channel->state &= ~HSI_CHANNEL_STATE_WRITING; + ev.event = HSI_EV_OUT; + ev.data = channel->tx_data; + ev.count = size; + spin_unlock(&channel->lock); + if_notify(dev->n_ch, &ev); +} + +int if_hsi_write(int ch, u32 *data, unsigned int count) +{ + int ret = 0; + struct if_hsi_channel *channel; + channel = &hsi_iface.channels[ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + spin_lock_bh(&hsi_iface.lock); + ret = if_hsi_write_on(ch, data, count); + spin_unlock_bh(&hsi_iface.lock); + return ret; +} + +void if_hsi_send_break(int ch) +{ + struct if_hsi_channel *channel; + channel = &hsi_iface.channels[ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + spin_lock_bh(&hsi_iface.lock); + hsi_ioctl(channel->dev, HSI_IOCTL_SEND_BREAK, NULL); + spin_unlock_bh(&hsi_iface.lock); +} + +void if_hsi_flush_rx(int ch) +{ + struct if_hsi_channel *channel; + channel = &hsi_iface.channels[ch]; + spin_lock_bh(&hsi_iface.lock); + hsi_ioctl(channel->dev, HSI_IOCTL_FLUSH_RX, NULL); + spin_unlock_bh(&hsi_iface.lock); +} + +void if_hsi_flush_ch(int ch) +{ + /* FIXME - Check the purpose of this function */ + struct if_hsi_channel *channel; + channel = &hsi_iface.channels[ch]; + spin_lock(&channel->lock); + spin_unlock(&channel->lock); +} + +void if_hsi_flush_tx(int ch) +{ + struct if_hsi_channel *channel; + channel = &hsi_iface.channels[ch]; + spin_lock_bh(&hsi_iface.lock); + hsi_ioctl(channel->dev, HSI_IOCTL_FLUSH_TX, NULL); + spin_unlock_bh(&hsi_iface.lock); +} + +void if_hsi_get_wakeline(int ch, unsigned int *state) +{ + struct if_hsi_channel *channel; + channel = &hsi_iface.channels[ch]; + spin_lock_bh(&hsi_iface.lock); + hsi_ioctl(channel->dev, HSI_IOCTL_WAKE, state); + spin_unlock_bh(&hsi_iface.lock); +} + +void if_hsi_set_wakeline(int ch, unsigned int state) +{ + struct if_hsi_channel *channel; + channel = &hsi_iface.channels[ch]; + spin_lock_bh(&hsi_iface.lock); + hsi_ioctl(channel->dev, state, NULL); + spin_unlock_bh(&hsi_iface.lock); +} + +int if_hsi_set_rx(int ch, struct hsi_rx_config *cfg) +{ + int ret; + struct if_hsi_channel *channel; + struct hsr_ctx ctx; + channel = &hsi_iface.channels[ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + RXCONV(&ctx, cfg); + spin_lock_bh(&hsi_iface.lock); + ret = hsi_ioctl(channel->dev, HSI_IOCTL_SET_RX, &ctx); + spin_unlock_bh(&hsi_iface.lock); + return ret; +} + +void if_hsi_get_rx(int ch, struct hsi_rx_config *cfg) +{ + struct if_hsi_channel *channel; + struct hsr_ctx ctx; + channel = &hsi_iface.channels[ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + spin_lock_bh(&hsi_iface.lock); + hsi_ioctl(channel->dev, HSI_IOCTL_GET_RX, &ctx); + RXCONV(cfg, &ctx); + spin_unlock_bh(&hsi_iface.lock); +} + +int if_hsi_set_tx(int ch, struct hsi_tx_config *cfg) +{ + int ret; + struct if_hsi_channel *channel; + struct hst_ctx ctx; + channel = &hsi_iface.channels[ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + TXCONV(&ctx, cfg); + spin_lock_bh(&hsi_iface.lock); + ret = hsi_ioctl(channel->dev, HSI_IOCTL_SET_TX, &ctx); + spin_unlock_bh(&hsi_iface.lock); + return ret; +} + +void if_hsi_get_tx(int ch, struct hsi_tx_config *cfg) +{ + struct if_hsi_channel *channel; + struct hst_ctx ctx; + channel = &hsi_iface.channels[ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + spin_lock_bh(&hsi_iface.lock); + hsi_ioctl(channel->dev, HSI_IOCTL_GET_TX, &ctx); + TXCONV(cfg, &ctx); + spin_unlock_bh(&hsi_iface.lock); +} + +void if_hsi_cancel_read(int ch) +{ + struct if_hsi_channel *channel; + channel = &hsi_iface.channels[ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + spin_lock(&channel->lock); + if (channel->state & HSI_CHANNEL_STATE_READING) + hsi_read_cancel(channel->dev); + channel->state &= ~HSI_CHANNEL_STATE_READING; + spin_unlock(&channel->lock); +} + +void if_hsi_cancel_write(int ch) +{ + struct if_hsi_channel *channel; + channel = &hsi_iface.channels[ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + spin_lock(&channel->lock); + if (channel->state & HSI_CHANNEL_STATE_WRITING) + hsi_write_cancel(channel->dev); + channel->state &= ~HSI_CHANNEL_STATE_WRITING; + spin_unlock(&channel->lock); +} + +static int if_hsi_openchannel(struct if_hsi_channel *channel) +{ + int ret = 0; + + spin_lock(&channel->lock); + + if (channel->state == HSI_CHANNEL_STATE_UNAVAIL) + return -ENODEV; + + if (channel->opened) { + ret = -EBUSY; + goto leave; + } + + if (!channel->dev) { + pr_err("Channel %d is not ready??\n", + channel->channel_id); + ret = -ENODEV; + goto leave; + } + + ret = hsi_open(channel->dev); + if (ret < 0) { + pr_err("Could not open channel %d\n", + channel->channel_id); + goto leave; + } + + channel->opened = 1; + +leave: + spin_unlock(&channel->lock); + return ret; +} + + +static int if_hsi_closechannel(struct if_hsi_channel *channel) +{ + int ret = 0; + + spin_lock(&channel->lock); + + if (!channel->opened) + goto leave; + + if (!channel->dev) { + pr_err("Channel %d is not ready??\n", + channel->channel_id); + ret = -ENODEV; + goto leave; + } + + /* Stop any pending read/write */ + if (channel->state & HSI_CHANNEL_STATE_READING) { + hsi_read_cancel(channel->dev); + channel->state &= ~HSI_CHANNEL_STATE_READING; + } + if (channel->state & HSI_CHANNEL_STATE_WRITING) { + hsi_write_cancel(channel->dev); + channel->state &= ~HSI_CHANNEL_STATE_WRITING; + } + + hsi_close(channel->dev); + + channel->opened = 0; +leave: + spin_unlock(&channel->lock); + return ret; +} + + +int if_hsi_start(int ch) +{ + struct if_hsi_channel *channel; + int ret = 0; + + channel = &hsi_iface.channels[ch]; + dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); + spin_lock_bh(&hsi_iface.lock); + channel->state = 0; + ret = if_hsi_openchannel(channel); + if (ret < 0) { + pr_err("Could not open channel %d\n", ch); + spin_unlock_bh(&hsi_iface.lock); + goto error; + } + spin_unlock_bh(&hsi_iface.lock); + if_hsi_poll(ch); + +error: + return ret; +} + +void if_hsi_stop(int ch) +{ + struct if_hsi_channel *channel; + channel = &hsi_iface.channels[ch]; + if_hsi_set_wakeline(ch, 1); + spin_lock_bh(&hsi_iface.lock); + if_hsi_closechannel(channel); + spin_unlock_bh(&hsi_iface.lock); +} + +static int __devinit if_hsi_probe(struct hsi_device *dev) +{ + struct if_hsi_channel *channel; + unsigned long *address; + int ret = -ENXIO, port; + + for (port = 0; port < HSI_MAX_PORTS; port++) { + if (if_hsi_char_driver.ch_mask[port]) + break; + } + + if (port == HSI_MAX_PORTS) + return -ENXIO; + + if (dev->n_ch >= HSI_MAX_CHAR_DEVS) { + pr_err("HSI char driver cannot handle channel %d\n", dev->n_ch); + return -ENXIO; + } + + address = &if_hsi_char_driver.ch_mask[port]; + + spin_lock_bh(&hsi_iface.lock); + if (test_bit(dev->n_ch, address) && (dev->n_p == port)) { + hsi_set_read_cb(dev, if_hsi_read_done); + hsi_set_write_cb(dev, if_hsi_write_done); + hsi_set_port_event_cb(dev, if_hsi_port_event); + channel = &hsi_iface.channels[dev->n_ch]; + channel->dev = dev; + channel->state = 0; + ret = 0; + hsi_iface.init_chan_map ^= (1 << dev->n_ch); + } + spin_unlock_bh(&hsi_iface.lock); + + return ret; +} + +static int __devexit if_hsi_remove(struct hsi_device *dev) +{ + struct if_hsi_channel *channel; + unsigned long *address; + int ret = -ENXIO, port; + + for (port = 0; port < HSI_MAX_PORTS; port++) { + if (if_hsi_char_driver.ch_mask[port]) + break; + } + + if (port == HSI_MAX_PORTS) + return -ENXIO; + + address = &if_hsi_char_driver.ch_mask[port]; + + spin_lock_bh(&hsi_iface.lock); + if (test_bit(dev->n_ch, address) && (dev->n_p == port)) { + hsi_set_read_cb(dev, NULL); + hsi_set_write_cb(dev, NULL); + channel = &hsi_iface.channels[dev->n_ch]; + channel->dev = NULL; + channel->state = HSI_CHANNEL_STATE_UNAVAIL; + ret = 0; + } + spin_unlock_bh(&hsi_iface.lock); + + return ret; +} + +static void if_hsi_port_event(struct hsi_device *dev, unsigned int event, + void *arg) +{ + struct hsi_event ev; + int i; + + ev.event = HSI_EV_EXCEP; + ev.data = (u32 *)0; + ev.count = 0; + + switch (event) { + case HSI_EVENT_BREAK_DETECTED: + pr_debug("%s, HWBREAK detected\n", __func__); + ev.data = (u32 *)HSI_HWBREAK; + spin_lock_bh(&hsi_iface.lock); + for (i = 0; i < HSI_MAX_CHAR_DEVS; i++) { + if (hsi_iface.channels[i].opened) + if_notify(i, &ev); + } + spin_unlock_bh(&hsi_iface.lock); + break; + case HSI_EVENT_HSR_DATAAVAILABLE: + i = (int)arg; + pr_debug("%s, HSI_EVENT_HSR_DATAAVAILABLE channel = %d\n", + __func__, i); + ev.event = HSI_EV_AVAIL; + spin_lock_bh(&hsi_iface.lock); + if (hsi_iface.channels[i].opened) + if_notify(i, &ev); + spin_unlock_bh(&hsi_iface.lock); + break; + case HSI_EVENT_CAWAKE_UP: + pr_debug("%s, CAWAKE up\n", __func__); + break; + case HSI_EVENT_CAWAKE_DOWN: + pr_debug("%s, CAWAKE down\n", __func__); + break; + case HSI_EVENT_ERROR: + pr_debug("%s, HSI ERROR occured\n", __func__); + break; + default: + pr_warning("%s, Unknown event(%d)\n", __func__, event); + break; + } +} + +int __init if_hsi_init(unsigned int port, unsigned int *channels_map) +{ + struct if_hsi_channel *channel; + int i, ret = 0; + + port -= 1; + if (port >= HSI_MAX_PORTS) + return -EINVAL; + + hsi_iface.bootstrap = 1; + spin_lock_init(&hsi_iface.lock); + + for (i = 0; i < HSI_MAX_PORTS; i++) + if_hsi_char_driver.ch_mask[i] = 0; + + for (i = 0; i < HSI_MAX_CHAR_DEVS; i++) { + channel = &hsi_iface.channels[i]; + channel->dev = NULL; + channel->opened = 0; + channel->state = 0; + channel->channel_id = i; + spin_lock_init(&channel->lock); + channel->state = HSI_CHANNEL_STATE_UNAVAIL; + } + + for (i = 0; (i < HSI_MAX_CHAR_DEVS) && channels_map[i]; i++) { + pr_debug("%s, port = %d, channels_map[i] = %d\n", __func__, + port, channels_map[i]); + if ((channels_map[i] - 1) < HSI_MAX_CHAR_DEVS) + if_hsi_char_driver.ch_mask[port] |= + (1 << ((channels_map[i] - 1))); + else { + pr_err("Channel %d cannot be handled by the HSI " + "driver.\n", channels_map[i]); + return -EINVAL; + } + + } + hsi_iface.init_chan_map = if_hsi_char_driver.ch_mask[port]; + + ret = hsi_register_driver(&if_hsi_char_driver); + if (ret) + pr_err("Error while registering HSI driver %d", ret); + + if (hsi_iface.init_chan_map) { + ret = -ENXIO; + pr_err("HSI: Some channels could not be registered (out of " + "range or already registered?)\n"); + } + return ret; +} + +int __exit if_hsi_exit(void) +{ + struct if_hsi_channel *channel; + unsigned long *address; + int i, port; + + for (port = 0; port < HSI_MAX_PORTS; port++) { + if (if_hsi_char_driver.ch_mask[port]) + break; + } + + if (port == HSI_MAX_PORTS) + return -ENXIO; + + address = &if_hsi_char_driver.ch_mask[port]; + + for (i = 0; i < HSI_MAX_CHAR_DEVS; i++) { + channel = &hsi_iface.channels[i]; + if (channel->opened) { + if_hsi_set_wakeline(i, 1); + if_hsi_closechannel(channel); + } + } + hsi_unregister_driver(&if_hsi_char_driver); + return 0; +} diff --git a/drivers/hsi/hsi-if.h b/drivers/hsi/hsi-if.h new file mode 100644 index 0000000..d64610d --- /dev/null +++ b/drivers/hsi/hsi-if.h @@ -0,0 +1,65 @@ +/* + * hsi-if.h + * + * Part of the HSI character driver, private headers. + * + * Copyright (C) 2009 Nokia Corporation. All rights reserved. + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Author: Andras Domokos + * Author: Sebastien JAN + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef _HSI_IF_H +#define _HSI_IF_H + +#define HSI_EV_MASK (0xffff << 0) +#define HSI_EV_TYPE_MASK (0x0f << 16) +#define HSI_EV_IN (0x01 << 16) +#define HSI_EV_OUT (0x02 << 16) +#define HSI_EV_EXCEP (0x03 << 16) +#define HSI_EV_AVAIL (0x04 << 16) +#define HSI_EV_TYPE(event) ((event) & HSI_EV_TYPE_MASK) + +#define HSI_HWBREAK 1 +#define HSI_ERROR 2 + +struct hsi_event { + unsigned int event; + u32 *data; + unsigned int count; +}; + +int if_hsi_init(unsigned int port, unsigned int *channels_map); +int if_hsi_exit(void); + +int if_hsi_start(int ch); +void if_hsi_stop(int ch); + +void if_hsi_send_break(int ch); +void if_hsi_flush_rx(int ch); +void if_hsi_flush_tx(int ch); +void if_hsi_bootstrap(int ch); +void if_hsi_set_wakeline(int ch, unsigned int state); +void if_hsi_get_wakeline(int ch, unsigned int *state); +int if_hsi_set_rx(int ch, struct hsi_rx_config *cfg); +void if_hsi_get_rx(int ch, struct hsi_rx_config *cfg); +int if_hsi_set_tx(int ch, struct hsi_tx_config *cfg); +void if_hsi_get_tx(int ch, struct hsi_tx_config *cfg); + +int if_hsi_read(int ch, u32 *data, unsigned int count); +int if_hsi_poll(int ch); +int if_hsi_write(int ch, u32 *data, unsigned int count); + +void if_hsi_cancel_read(int ch); +void if_hsi_cancel_write(int ch); + +#endif /* _HSI_IF_H */