/***************************************************************************/
/*                             Druckersoftware                             */
/*                    Copyright (C) Carl Valentin GmbH                     */
/***************************************************************************/

/*
 * KM_DmaChan_MappedIo.c
 *
 *  Created on: May 31, 2016
 *      Author: preitinger
 */


/*. IMPORT ================================================================*/
#include "KM_DmaChan_MappedIo.h"

#include "KM_CvKernelAccess.h" // zumindest wegen ASSERT
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/io-mapping.h>
//#include <linux/dma-mapping.h>
#include <linux/bitops.h>

//#include <../arch/arm/plat-omap/include/plat/dmtimer.h>

/*. ENDIMPORT =============================================================*/

/*. LOCAL =================================================================*/

/*-------------------------------- Makros ---------------------------------*/

/*--------------------------- Typdeklarationen ----------------------------*/

/*------------------------------ Prototypen -------------------------------*/

/*------------------------ Konstantendeklarationen ------------------------*/

/*------------------------- modulglobale Variable -------------------------*/

/*. ENDLOCAL ==============================================================*/


int
DmaChan_MappedIo_create(DmaChan_MappedIo* this, phys_addr_t physAddr, unsigned long size)
{
	if (unlikely(physAddr & (PAGE_SIZE - 1))) {
		pr_err("%s: physAddr %u not page aligned (PAGE_SIZE=%lu)\n", __func__, physAddr, PAGE_SIZE);
		return -1;
	}

	if (unlikely(size & (PAGE_SIZE - 1))) {
		pr_err("%s: size %lu not page aligned (PAGE_SIZE=%lu)\n", __func__, size, PAGE_SIZE);
		return -1;
	}

	this->_map = io_mapping_create_wc(physAddr, size);

	if (unlikely(!this->_map)) {
		pr_err("%s: could not create io mapping for (%u, %lu)\n", __func__, physAddr, size);
		return -1;
	}

	this->_a = io_mapping_map_wc(this->_map, 0, size);
	if (unlikely(!this->_a)) {
		pr_err("%s: io_mapping_map_wc returned 0!\n", __func__);
		io_mapping_free(this->_map);
		this->_map = NULL;
		return -1;
	}

	this->_size = size;
	return 0;
}

void
DmaChan_MappedIo_delete(DmaChan_MappedIo* this)
{
	this->_size = 0;
	io_mapping_unmap(this->_a);
	this->_a = NULL;
	io_mapping_free(this->_map);
	this->_map = NULL;
}

void
DmaChan_MappedIo_set32(DmaChan_MappedIo* this, unsigned long off, uint32_t value)
{
	ASSERT(off >= 0 && off < this->_size);
	ASSERT((off & 3) == 0);
	iowrite32(value, this->_a + off);
}

uint32_t
DmaChan_MappedIo_get32(DmaChan_MappedIo* this, unsigned long off)
{
	ASSERT(off >= 0 && off < this->_size);
	ASSERT((off & 3) == 0);
	return ioread32(this->_a + off);
}

void
DmaChan_MappedIo_set16(DmaChan_MappedIo* this, unsigned long off, uint16_t value) {
	ASSERT(off >= 0 && off < this->_size);
	ASSERT((off & 1) == 0);

	iowrite16(value, this->_a + off);
}

uint16_t
DmaChan_MappedIo_get16(DmaChan_MappedIo* this, unsigned long off) {
	ASSERT(off >= 0 && off < this->_size);
	ASSERT((off & 1) == 0);

	return ioread16(this->_a + off);
}

void DmaChan_MappedIo_set(DmaChan_MappedIo* this, unsigned long offTo, const void* from, size_t count) {
    memcpy_toio(this->_a + offTo, from, count);
}

void DmaChan_MappedIo_get(DmaChan_MappedIo* this, unsigned long offFrom, void* to, size_t count) {
    memcpy_fromio(to, this->_a + offFrom, count);
}

EXPORT_SYMBOL(DmaChan_MappedIo_create);
EXPORT_SYMBOL(DmaChan_MappedIo_delete);
EXPORT_SYMBOL(DmaChan_MappedIo_set32);
EXPORT_SYMBOL(DmaChan_MappedIo_get32);
EXPORT_SYMBOL(DmaChan_MappedIo_set16);
EXPORT_SYMBOL(DmaChan_MappedIo_get16);
