mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-11-16 12:34:45 +00:00
@@ -19,6 +19,7 @@
|
|||||||
#include <drvmgr/drvmgr.h>
|
#include <drvmgr/drvmgr.h>
|
||||||
#include <grlib/ambapp_bus.h>
|
#include <grlib/ambapp_bus.h>
|
||||||
#include <grlib/occan.h>
|
#include <grlib/occan.h>
|
||||||
|
#include <grlib/canbtrs.h>
|
||||||
|
|
||||||
#include <grlib/grlib_impl.h>
|
#include <grlib/grlib_impl.h>
|
||||||
|
|
||||||
@@ -185,19 +186,20 @@ typedef struct {
|
|||||||
#define pelican_regs pelican32_regs
|
#define pelican_regs pelican32_regs
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Default sampling point in % */
|
||||||
|
#define OCCAN_SAMPLING_POINT 90
|
||||||
|
|
||||||
#define MAX_TSEG2 7
|
/* OCCAN baud-rate paramter boundaries */
|
||||||
#define MAX_TSEG1 15
|
struct grlib_canbtrs_ranges occan_btrs_ranges = {
|
||||||
|
.max_scaler = 64,
|
||||||
|
.has_bpr = 0,
|
||||||
|
.divfactor = 1,
|
||||||
|
.min_tseg1 = 1,
|
||||||
|
.max_tseg1 = 16,
|
||||||
|
.min_tseg2 = 1,
|
||||||
|
.max_tseg2 = 8,
|
||||||
|
};
|
||||||
|
|
||||||
#if 0
|
|
||||||
typedef struct {
|
|
||||||
unsigned char brp;
|
|
||||||
unsigned char sjw;
|
|
||||||
unsigned char tseg1;
|
|
||||||
unsigned char tseg2;
|
|
||||||
unsigned char sam;
|
|
||||||
} occan_speed_regs;
|
|
||||||
#endif
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char btr0;
|
unsigned char btr0;
|
||||||
unsigned char btr1;
|
unsigned char btr1;
|
||||||
@@ -251,7 +253,9 @@ static CANMsg *occan_fifo_claim_get(occan_fifo *fifo);
|
|||||||
static void occan_fifo_clr(occan_fifo *fifo);
|
static void occan_fifo_clr(occan_fifo *fifo);
|
||||||
|
|
||||||
/**** Hardware related Interface ****/
|
/**** Hardware related Interface ****/
|
||||||
static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result);
|
static void convert_timing_to_btrs(
|
||||||
|
struct grlib_canbtrs_timing *t,
|
||||||
|
occan_speed_regs *btrs);
|
||||||
static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing);
|
static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing);
|
||||||
static void pelican_init(occan_priv *priv);
|
static void pelican_init(occan_priv *priv);
|
||||||
static void pelican_open(occan_priv *priv);
|
static void pelican_open(occan_priv *priv);
|
||||||
@@ -765,6 +769,7 @@ static void pelican_init(occan_priv *priv){
|
|||||||
|
|
||||||
static void pelican_open(occan_priv *priv){
|
static void pelican_open(occan_priv *priv){
|
||||||
int ret;
|
int ret;
|
||||||
|
struct grlib_canbtrs_timing timing;
|
||||||
|
|
||||||
/* Set defaults */
|
/* Set defaults */
|
||||||
priv->speed = OCCAN_SPEED_250K;
|
priv->speed = OCCAN_SPEED_250K;
|
||||||
@@ -783,13 +788,19 @@ static void pelican_open(occan_priv *priv){
|
|||||||
*/
|
*/
|
||||||
WRITE_REG(priv, &priv->regs->clkdiv, (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV));
|
WRITE_REG(priv, &priv->regs->clkdiv, (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV));
|
||||||
|
|
||||||
ret = occan_calc_speedregs(priv->sys_freq_hz,priv->speed,&priv->timing);
|
ret = grlib_canbtrs_calc_timing(
|
||||||
if ( ret ){
|
priv->speed, priv->sys_freq_hz,
|
||||||
|
OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
|
||||||
|
(struct grlib_canbtrs_timing *)&timing);
|
||||||
|
if ( ret ) {
|
||||||
/* failed to set speed for this system freq, try with 50K instead */
|
/* failed to set speed for this system freq, try with 50K instead */
|
||||||
priv->speed = OCCAN_SPEED_50K;
|
priv->speed = OCCAN_SPEED_50K;
|
||||||
occan_calc_speedregs(priv->sys_freq_hz, priv->speed,
|
grlib_canbtrs_calc_timing(
|
||||||
&priv->timing);
|
priv->speed, priv->sys_freq_hz,
|
||||||
|
OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
|
||||||
|
(struct grlib_canbtrs_timing *)&timing);
|
||||||
}
|
}
|
||||||
|
convert_timing_to_btrs(&timing, &priv->timing);
|
||||||
|
|
||||||
/* disable all interrupts */
|
/* disable all interrupts */
|
||||||
WRITE_REG(priv, &priv->regs->inten, 0);
|
WRITE_REG(priv, &priv->regs->inten, 0);
|
||||||
@@ -983,97 +994,13 @@ static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned
|
|||||||
WRITE_REG(priv, amask3, amask[3]);
|
WRITE_REG(priv, amask3, amask[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void convert_timing_to_btrs(
|
||||||
/* This function calculates BTR0 and BTR1 values for a given bitrate.
|
struct grlib_canbtrs_timing *t,
|
||||||
*
|
occan_speed_regs *btrs)
|
||||||
* Set communication parameters.
|
|
||||||
* \param clock_hz OC_CAN Core frequency in Hz.
|
|
||||||
* \param rate Requested baud rate in bits/second.
|
|
||||||
* \param result Pointer to where resulting BTRs will be stored.
|
|
||||||
* \return zero if successful to calculate a baud rate.
|
|
||||||
*/
|
|
||||||
static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result)
|
|
||||||
{
|
{
|
||||||
int best_error = 1000000000;
|
btrs->btr0 = (t->rsj << OCCAN_BUSTIM_SJW_BIT) |
|
||||||
int error;
|
(t->scaler & OCCAN_BUSTIM_BRP);
|
||||||
int best_tseg=0, best_brp=0, brp=0;
|
btrs->btr1 = (0<<7) | (t->ps2 << OCCAN_BUSTIM_TSEG2_BIT) | t->ps1;
|
||||||
int tseg=0, tseg1=0, tseg2=0;
|
|
||||||
int sjw = 0;
|
|
||||||
int clock = clock_hz / 2;
|
|
||||||
int sampl_pt = 90;
|
|
||||||
|
|
||||||
if ( (rate<5000) || (rate>1000000) ){
|
|
||||||
/* invalid speed mode */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find best match, return -2 if no good reg
|
|
||||||
* combination is available for this frequency */
|
|
||||||
|
|
||||||
/* some heuristic specials */
|
|
||||||
if (rate > ((1000000 + 500000) / 2))
|
|
||||||
sampl_pt = 75;
|
|
||||||
|
|
||||||
if (rate < ((12500 + 10000) / 2))
|
|
||||||
sampl_pt = 75;
|
|
||||||
|
|
||||||
if (rate < ((100000 + 125000) / 2))
|
|
||||||
sjw = 1;
|
|
||||||
|
|
||||||
/* tseg even = round down, odd = round up */
|
|
||||||
for (tseg = (0 + 0 + 2) * 2;
|
|
||||||
tseg <= (MAX_TSEG2 + MAX_TSEG1 + 2) * 2 + 1;
|
|
||||||
tseg++)
|
|
||||||
{
|
|
||||||
brp = clock / ((1 + tseg / 2) * rate) + tseg % 2;
|
|
||||||
if ((brp == 0) || (brp > 64))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
error = rate - clock / (brp * (1 + tseg / 2));
|
|
||||||
if (error < 0)
|
|
||||||
{
|
|
||||||
error = -error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error <= best_error)
|
|
||||||
{
|
|
||||||
best_error = error;
|
|
||||||
best_tseg = tseg/2;
|
|
||||||
best_brp = brp-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (best_error && (rate / best_error < 10))
|
|
||||||
{
|
|
||||||
printk("OCCAN: bitrate %d is not possible with %d Hz clock\n\r",rate, clock);
|
|
||||||
return -2;
|
|
||||||
}else if ( !result )
|
|
||||||
return 0; /* nothing to store result in, but a valid bitrate can be calculated */
|
|
||||||
|
|
||||||
tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100;
|
|
||||||
|
|
||||||
if (tseg2 < 0)
|
|
||||||
{
|
|
||||||
tseg2 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tseg2 > MAX_TSEG2)
|
|
||||||
{
|
|
||||||
tseg2 = MAX_TSEG2;
|
|
||||||
}
|
|
||||||
|
|
||||||
tseg1 = best_tseg - tseg2 - 2;
|
|
||||||
|
|
||||||
if (tseg1 > MAX_TSEG1)
|
|
||||||
{
|
|
||||||
tseg1 = MAX_TSEG1;
|
|
||||||
tseg2 = best_tseg - tseg1 - 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
result->btr0 = (sjw<<OCCAN_BUSTIM_SJW_BIT) | (best_brp&OCCAN_BUSTIM_BRP);
|
|
||||||
result->btr1 = (0<<7) | (tseg2<<OCCAN_BUSTIM_TSEG2_BIT) | tseg1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing)
|
static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing)
|
||||||
@@ -1441,7 +1368,7 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
|
|||||||
static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
|
static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
occan_speed_regs timing;
|
struct grlib_canbtrs_timing timing;
|
||||||
occan_priv *can;
|
occan_priv *can;
|
||||||
struct drvmgr_dev *dev;
|
struct drvmgr_dev *dev;
|
||||||
unsigned int speed;
|
unsigned int speed;
|
||||||
@@ -1467,7 +1394,11 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
|
|||||||
|
|
||||||
/* get speed rate from argument */
|
/* get speed rate from argument */
|
||||||
speed = (unsigned int)ioarg->buffer;
|
speed = (unsigned int)ioarg->buffer;
|
||||||
ret = occan_calc_speedregs(can->sys_freq_hz,speed,&timing);
|
/* Calculate default timing register values */
|
||||||
|
ret = grlib_canbtrs_calc_timing(
|
||||||
|
speed, can->sys_freq_hz,
|
||||||
|
OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
|
||||||
|
(struct grlib_canbtrs_timing *)&timing);
|
||||||
if ( ret )
|
if ( ret )
|
||||||
return RTEMS_INVALID_NAME; /* EINVAL */
|
return RTEMS_INVALID_NAME; /* EINVAL */
|
||||||
|
|
||||||
@@ -1476,7 +1407,7 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
|
|||||||
|
|
||||||
/* save timing/speed */
|
/* save timing/speed */
|
||||||
can->speed = speed;
|
can->speed = speed;
|
||||||
can->timing = timing;
|
convert_timing_to_btrs(&timing, &can->timing);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OCCAN_IOC_SET_BTRS:
|
case OCCAN_IOC_SET_BTRS:
|
||||||
|
|||||||
Reference in New Issue
Block a user